<commit_before>// If this code works, it was written by Ticki. If it does not, I don't know who the hell wrote it
// but it was definitively not me. Blame someone else.

#[deny(warnings)]

use std::io::{self, Write, Read};
use std::error::Error;
use std::process::exit;

#[derive(Copy, Clone)]
struct Trailing {
    chars: [u8; 4],
    current: usize,
}

// Wow, such premature, much optimization
impl Trailing {
    #[inline]
    fn new() -> Trailing {
        Trailing {
            chars: [0; 4],
            current: 0,
        }
    }

    fn set(&mut self, b: u8) -> bool {
        self.chars[self.current] = b;
        self.current += 1;

        self.is_complete()
    }

    fn reset(&mut self) {
        self.current = 0;
    }

    fn is_complete(self) -> bool {
        self.current == 4
    }

    fn chars(self) -> [u8; 4] {
        self.chars
    }
}

trait IsPrintable {
    fn is_printable(self) -> bool;
}

impl IsPrintable for u8 {
    fn is_printable(self) -> bool {
        // TODO handle unicode.
        self >= 0x20 && self <= 0x7e
    }
}

trait Try {
    type Succ;

    fn try(self) -> Self::Succ;
}

impl<T, U: Error> Try for Result<T, U> {
    type Succ = T;

    fn try(self) -> T {
        match self {
            Ok(succ) => succ,
            Err(e) => {
                println!("error: {}", e.description());
                exit(128 + 1);
            },
        }
    }
}

fn main() {
    let mut trailing = Trailing::new();
    let mut stdout = io::stdout();

    for i in io::stdin().bytes().map(|x| x.try()) {
        if i.is_printable() {
            if trailing.is_complete() {
                stdout.write(&[i]).try();
            } else if trailing.set(i) {
                stdout.write(&trailing.chars()).try();
            }
        } else {
            if trailing.is_complete() {
                stdout.write(&[b'\n']).try();
            }
            trailing.reset();
        }
    }
}
<commit_msg>Add man entry, allow reading from arbitrary file paths instead of just stdin, error handling<commit_after>// If this code works, it was written by Ticki. If it does not, I don't know who the hell wrote it
// but it was definitively not me. Blame someone else.

#[deny(warnings)]
#[deny(unused_mut)]

use std::env;
use std::error::Error;
use std::fs;
use std::io::{self, Write, Read};
use std::process::exit;

#[derive(Copy, Clone)]
struct Trailing {
    chars: [u8; 4],
    current: usize,
}

// Wow, such premature, much optimization
impl Trailing {
    #[inline]
    fn new() -> Trailing {
        Trailing {
            chars: [0; 4],
            current: 0,
        }
    }

    fn set(&mut self, b: u8) -> bool {
        self.chars[self.current] = b;
        self.current += 1;

        self.is_complete()
    }

    fn reset(&mut self) {
        self.current = 0;
    }

    fn is_complete(self) -> bool {
        self.current == 4
    }

    fn chars(self) -> [u8; 4] {
        self.chars
    }
}

trait IsPrintable {
    fn is_printable(self) -> bool;
}

impl IsPrintable for u8 {
    fn is_printable(self) -> bool {
        // TODO handle unicode.
        self >= 0x20 && self <= 0x7e
    }
}

trait Try {
    type Succ;

    fn try(self) -> Self::Succ;
}

impl<T, U: Error> Try for Result<T, U> {
    type Succ = T;

    fn try(self) -> T {
        match self {
            Ok(succ) => succ,
            Err(e) => {
                println!("error: {}", e.description());
                exit(1);
            },
        }
    }
}

fn read<R: Read, W: Write>(stdin: R, mut stdout: W) {
    let mut trailing = Trailing::new();

    for i in stdin.bytes().map(|x| x.try()) {
        if i.is_printable() {
            if trailing.is_complete() {
                stdout.write(&[i]).try();
            } else if trailing.set(i) {
                stdout.write(&trailing.chars()).try();
            }
        } else {
            if trailing.is_complete() {
                stdout.write(&[b'\n']).try();
            }
            trailing.reset();
        }
    }
}

const HELP: &'static [u8] = br#"
    NAME
        strings - inspect a binary file for strings of printable characters.
    SYNOPSIS
        strings [-h | --help] [FILE]
    DESCRIPTION
        This utility will read the file from the path given in the argument. If no argument is given, 'strings' will read from the standard input. The byte stream is then inspected for contiguous, printable ASCII characters of length 4 or more. These strings of printable characters are written to the standard output. Each contiguous strings are seperated by a newline (0x0A).

        This utility is useful for inspecting binary files for human readable information, to determine the contents.

        This is a clone of GNU strings, though they differ in a number of ways.
    OPTIONS
        -h
        --help
            Print this manual page.
    COPYRIGHT
        Copyright (c) 2016 Ticki

        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#;

fn main() {
    let mut stdout = io::stdout();
    let mut args = env::args();
    if args.len() > 2 {
        println!("error: Too many arguments. Try 'strings -h'.");
        exit(1);
    }

    match args.nth(1) {
        None => read(io::stdin(), stdout),
        Some(a) => match a.as_ref() {
            "-h" | "--help" => {
                stdout.write(HELP).try();
            },
            f => read(fs::File::open(f).try(), stdout),
        },
    }
}
<|endoftext|>


<commit_before>pub use super::zfile::ArgType;
pub use super::zfile::JumpType;
pub use super::zfile::Zjump;
pub use super::zfile::Zfile;
pub use super::zfile::{ Operand, Variable, Constant, LargeConstant };

/// clears spcified window
pub fn op_erase_window(value: i8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::LargeConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x0d, args);

    // signed to unsigned value
    write_u16(value as u16, &mut bytes);
    bytes
}

/// calls a routine (the address is stored in a variable)
pub fn op_call_1n_var(variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x0f, ArgType::Variable);
    //self.add_jump(jump_to_label.to_string(), JumpType::Routine);
    bytes.push(variable);
    bytes
}

/// stores a value to an array
/// stores the value of variable to the address in: array_address + 2*index
pub fn op_storew(array_address: &Operand, index: &Variable, variable: &Variable) -> Vec<u8> {
    // assert!(array_address > 0, "not allowed array-address, becouse in _some_ interpreters (for example zoom) it crahs. -.-");
    let args: Vec<ArgType> = vec![arg_type(&array_address), ArgType::Variable, ArgType::Variable, ArgType::Nothing];
    let mut bytes = op_var(0x01, args);

    // array address
    write_argument(array_address, &mut bytes);

    // array index
    bytes.push(index.id);

    // value
    bytes.push(variable.id);
    bytes
}

/// loads a word from an array in a variable
/// loadw is an 2op, BUT with 3 ops -.-
pub fn op_loadw(array_address: &Operand, index: &Variable, variable: &Variable) -> Vec<u8> {
    let mut bytes = op_2(0x0f, vec![arg_type(&array_address), ArgType::Variable]);

    // array address
    write_argument(array_address, &mut bytes);
    // array index
    bytes.push(index.id);

    // variable
    bytes.push(variable.id);
    bytes
}

/// reads keys from the keyboard and saves the asci-value in local_var_id
/// read_char is VAROP
pub fn op_read_char(local_var_id: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x16, args);

    // write argument value
    bytes.push(0x00);

    // write varible id
    bytes.push(local_var_id);
    bytes
}

/// set the style of the text
pub fn op_set_text_style(bold: bool, reverse: bool, monospace: bool, italic: bool) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x11, args);

    let mut style_byte : u8;
    style_byte = 0x00;
    if bold {
        style_byte |=0x02
    }
     if reverse {
        style_byte |=0x01
    }
     if monospace {
        style_byte |=0x08
    }
     if italic {
        style_byte |=0x04
    }
    bytes.push(style_byte);
    bytes
}

/// Prints the value of a variable (only ints a possibe)
pub fn op_print_num_var(variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Variable, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x06, args);
    bytes.push(variable.id);
    bytes
}

/// pulls an value off the stack to an variable
/// SmallConst because pull takes an reference to an variable
pub fn op_pull(variable: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x09, args);
    bytes.push(variable);
    bytes
}

/// calculates a random numer from 1 to range
pub fn op_random(range: &Operand, variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(range), ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x07, args);
    write_argument(range, &mut bytes);
    bytes.push(variable.id);
    bytes
}

/// pushs an u16 value (for example an address) on the stack
pub fn op_push_u16(value: u16) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::LargeConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x08, args);
    write_u16(value, &mut bytes);
    bytes
}

/// sets the colors of the foreground (font) and background (but with variables
pub fn op_set_color_var(foreground: u8, background: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Variable, ArgType::Variable];
    let mut bytes = op_2(0x1b, args);
    bytes.push(foreground);
    bytes.push(background);
    bytes
}

/// sets the colors of the foreground (font) and background
pub fn op_set_color(foreground: u8, background: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::SmallConst];
    let mut bytes = op_2(0x1b, args);
    bytes.push(foreground);
    bytes.push(background);
    bytes
}

/// prints string at given packed address (which is then multiplied by 8 the zmachine to be the real address)
pub fn op_print_paddr(address: &Operand) -> Vec<u8> {
   let mut bytes = op_1(0x0D, arg_type(&address));
   write_argument(address, &mut bytes);
   bytes
}

/// prints string at given adress
pub fn op_print_addr(address: &Operand) -> Vec<u8> {
   let mut bytes = op_1(0x07, arg_type(&address));
   write_argument(address, &mut bytes);
   bytes
}

/// returns a LargeConst
pub fn op_ret(value: u16) -> Vec<u8> {
    let mut bytes = op_1(0x0b, ArgType::LargeConst);
    write_u16(value, &mut bytes);
    bytes
}

// saves an u8 to the variable
pub fn op_store_var(variable: &Variable, value: &Operand) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Reference, arg_type(&value)];
    let mut bytes = op_2(0x0d, args);
    bytes.push(variable.id);
    write_argument(value, &mut bytes);
    bytes
}

/// bitwise or
/// save_variable = operand1 | operand2
pub fn op_or(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x08, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// bitwise and
/// save_variable = operand1 & operand2
pub fn op_and(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x09, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// subtraktion
/// save_variable = operand1 - operand2
pub fn op_sub(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x15, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// addition
/// save_variable = operand1 + operand2
pub fn op_add(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x14, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// decrements the value of the variable
pub fn op_dec(variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x06, ArgType::Reference);
    bytes.push(variable);
    bytes
}

/// increments the value of the variable
pub fn op_inc( variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x05, ArgType::Reference);
    bytes.push(variable);
    bytes
}

pub fn op_newline() -> Vec<u8> {
    op_0(0x0b)
}

pub fn quit() -> Vec<u8> {
    op_0(0x0a)
}

/// op-codes with 0 operators
/// $b0 -- $bf  short     0OP
pub fn op_0(value: u8) -> Vec<u8> {
    let byte = value | 0xb0;
    vec![byte]
}

/// op-codes with variable operators (4 are possible)
/// $e0 -- $ff  variable  VAR     (operand types in next byte(s))
pub fn op_var(value: u8, arg_types: Vec<ArgType>) -> Vec<u8> {
	let mut ret = Vec::new();
	ret.push(value | 0xe0);
    ret.push(encode_variable_arguments(arg_types));
    ret
}

/// op-codes with 1 operator
/// $80 -- $8f  short     1OP     large constant
/// $90 -- $9f  short     1OP     small constant
/// $a0 -- $af  short     1OP     variable
pub fn op_1( value: u8, arg_type: ArgType) -> Vec<u8> {
    let byte: u8 = match arg_type {
        ArgType::Reference  => 0x90 | value,  // same as SmallConst
        ArgType::Variable   => 0xa0 | value,
        ArgType::SmallConst => 0x90 | value,
        ArgType::LargeConst => 0x80 | value,
        _                   => panic!("no possible 1OP")
    };

    vec![byte]
}

/// $00 -- $1f  long      2OP     small constant, small constant
/// $20 -- $3f  long      2OP     small constant, variable
/// $40 -- $5f  long      2OP     variable, small constant
/// $60 -- $7f  long      2OP     variable, variable
///
/// $c0 -- $df  variable  2OP     (operand types in next byte)
/// not handled here: $be  extended opcode given in next byte
pub fn op_2( value: u8, arg_types: Vec<ArgType>) -> Vec<u8> {
    let mut byte: u8 = 0x00;
    let mut is_variable: bool = false;
    let mut ret = Vec::new();
    for (i, arg_type) in arg_types.iter().enumerate() {
        let shift: u8 = 6 - i as u8;
        match arg_type {
            &ArgType::SmallConst => byte |= 0x00 << shift,
            &ArgType::Variable   => byte |= 0x01 << shift,
            &ArgType::Reference  => byte |= 0x00 << shift,
            &ArgType::LargeConst => is_variable = true,
            _                    => panic!("no possible 2OP")
        }
    }

    if is_variable {
        let mut byte: u8 = 0xc0 | value;
        byte = byte | value;
        ret.push(byte);

        let mut byte2 = encode_variable_arguments(arg_types);
        byte2 = byte2 | 0xf;
        ret.push(byte2)
    } else {
        byte = byte | value;
        ret.push(byte)
    }
    ret
}

pub fn encode_variable_arguments( arg_types: Vec<ArgType>) -> u8 {
    let mut byte: u8 = 0x00;
    for (i, arg_type) in arg_types.iter().enumerate() {
        let shift: u8 = 6 - 2 * i as u8;
        match arg_type {
            &ArgType::LargeConst => byte |= 0x00 << shift,
            &ArgType::SmallConst => byte |= 0x01 << shift,
            &ArgType::Variable   => byte |= 0x02 << shift,
            &ArgType::Nothing    => byte |= 0x03 << shift,
            &ArgType::Reference  => byte |= 0x01 << shift,
            //_                    => panic!("no possible varOP")
        }
    }

    byte
 }

pub fn arg_type(operand: &Operand) -> ArgType {
    match operand {
        &Operand::Var(_) => ArgType::Variable,
        &Operand::Const(_) => ArgType::SmallConst,
        &Operand::LargeConst(_) => ArgType::LargeConst
    }
}

pub fn write_argument(operand: &Operand, v: &mut Vec<u8>){
    match operand {
        &Operand::Var(ref var)=> v.push(var.id),
        &Operand::Const(ref constant) => v.push(constant.value),
        &Operand::LargeConst(ref constant) => write_i16(constant.value, v)
    };
}

///writes u16 to a vec<u8>
pub fn write_u16(value: u16, v: &mut Vec<u8>) {
        v.push((value >> 8) as u8);
        v.push((value & 0xff) as u8);
}

///writes u16 to a vec<u8>
pub fn write_i16(value: i16, v: &mut Vec<u8>) {
        v.push((value >> 8) as u8);
        v.push((value & 0xff) as u8);
}
<commit_msg>added op_mul op_div<commit_after>pub use super::zfile::ArgType;
pub use super::zfile::JumpType;
pub use super::zfile::Zjump;
pub use super::zfile::Zfile;
pub use super::zfile::{ Operand, Variable, Constant, LargeConstant };

/// clears spcified window
pub fn op_erase_window(value: i8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::LargeConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x0d, args);

    // signed to unsigned value
    write_u16(value as u16, &mut bytes);
    bytes
}

/// calls a routine (the address is stored in a variable)
pub fn op_call_1n_var(variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x0f, ArgType::Variable);
    //self.add_jump(jump_to_label.to_string(), JumpType::Routine);
    bytes.push(variable);
    bytes
}

/// stores a value to an array
/// stores the value of variable to the address in: array_address + 2*index
pub fn op_storew(array_address: &Operand, index: &Variable, variable: &Variable) -> Vec<u8> {
    // assert!(array_address > 0, "not allowed array-address, becouse in _some_ interpreters (for example zoom) it crahs. -.-");
    let args: Vec<ArgType> = vec![arg_type(&array_address), ArgType::Variable, ArgType::Variable, ArgType::Nothing];
    let mut bytes = op_var(0x01, args);

    // array address
    write_argument(array_address, &mut bytes);

    // array index
    bytes.push(index.id);

    // value
    bytes.push(variable.id);
    bytes
}

/// loads a word from an array in a variable
/// loadw is an 2op, BUT with 3 ops -.-
pub fn op_loadw(array_address: &Operand, index: &Variable, variable: &Variable) -> Vec<u8> {
    let mut bytes = op_2(0x0f, vec![arg_type(&array_address), ArgType::Variable]);

    // array address
    write_argument(array_address, &mut bytes);
    // array index
    bytes.push(index.id);

    // variable
    bytes.push(variable.id);
    bytes
}

/// reads keys from the keyboard and saves the asci-value in local_var_id
/// read_char is VAROP
pub fn op_read_char(local_var_id: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x16, args);

    // write argument value
    bytes.push(0x00);

    // write varible id
    bytes.push(local_var_id);
    bytes
}

/// set the style of the text
pub fn op_set_text_style(bold: bool, reverse: bool, monospace: bool, italic: bool) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x11, args);

    let mut style_byte : u8;
    style_byte = 0x00;
    if bold {
        style_byte |=0x02
    }
     if reverse {
        style_byte |=0x01
    }
     if monospace {
        style_byte |=0x08
    }
     if italic {
        style_byte |=0x04
    }
    bytes.push(style_byte);
    bytes
}

/// Prints the value of a variable (only ints a possibe)
pub fn op_print_num_var(variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Variable, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x06, args);
    bytes.push(variable.id);
    bytes
}

/// pulls an value off the stack to an variable
/// SmallConst because pull takes an reference to an variable
pub fn op_pull(variable: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x09, args);
    bytes.push(variable);
    bytes
}

/// calculates a random numer from 1 to range
pub fn op_random(range: &Operand, variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(range), ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x07, args);
    write_argument(range, &mut bytes);
    bytes.push(variable.id);
    bytes
}

/// pushs an u16 value (for example an address) on the stack
pub fn op_push_u16(value: u16) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::LargeConst, ArgType::Nothing, ArgType::Nothing, ArgType::Nothing];
    let mut bytes = op_var(0x08, args);
    write_u16(value, &mut bytes);
    bytes
}

/// sets the colors of the foreground (font) and background (but with variables
pub fn op_set_color_var(foreground: u8, background: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Variable, ArgType::Variable];
    let mut bytes = op_2(0x1b, args);
    bytes.push(foreground);
    bytes.push(background);
    bytes
}

/// sets the colors of the foreground (font) and background
pub fn op_set_color(foreground: u8, background: u8) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::SmallConst, ArgType::SmallConst];
    let mut bytes = op_2(0x1b, args);
    bytes.push(foreground);
    bytes.push(background);
    bytes
}

/// prints string at given packed address (which is then multiplied by 8 the zmachine to be the real address)
pub fn op_print_paddr(address: &Operand) -> Vec<u8> {
   let mut bytes = op_1(0x0D, arg_type(&address));
   write_argument(address, &mut bytes);
   bytes
}

/// prints string at given adress
pub fn op_print_addr(address: &Operand) -> Vec<u8> {
   let mut bytes = op_1(0x07, arg_type(&address));
   write_argument(address, &mut bytes);
   bytes
}

/// returns a LargeConst
pub fn op_ret(value: u16) -> Vec<u8> {
    let mut bytes = op_1(0x0b, ArgType::LargeConst);
    write_u16(value, &mut bytes);
    bytes
}

// saves an u8 to the variable
pub fn op_store_var(variable: &Variable, value: &Operand) -> Vec<u8> {
    let args: Vec<ArgType> = vec![ArgType::Reference, arg_type(&value)];
    let mut bytes = op_2(0x0d, args);
    bytes.push(variable.id);
    write_argument(value, &mut bytes);
    bytes
}

/// bitwise or
/// save_variable = operand1 | operand2
pub fn op_or(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x08, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// bitwise and
/// save_variable = operand1 & operand2
pub fn op_and(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x09, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// subtraktion
/// save_variable = operand1 - operand2
pub fn op_sub(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x15, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// addition
/// save_variable = operand1 + operand2
pub fn op_add(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x14, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// multiplikation
/// save_variable = operand1 * operand2
pub fn op_mul(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x16, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// division
/// save_variable = operand1 / operand2
pub fn op_mul(operand1: &Operand, operand2: &Operand, save_variable: &Variable) -> Vec<u8> {
    let args: Vec<ArgType> = vec![arg_type(operand1), arg_type(operand2)];
    let mut bytes = op_2(0x17, args);
    write_argument(operand1, &mut bytes);
    write_argument(operand2, &mut bytes);
    bytes.push(save_variable.id);
    bytes
}

/// decrements the value of the variable
pub fn op_dec(variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x06, ArgType::Reference);
    bytes.push(variable);
    bytes
}

/// increments the value of the variable
pub fn op_inc( variable: u8) -> Vec<u8> {
    let mut bytes = op_1(0x05, ArgType::Reference);
    bytes.push(variable);
    bytes
}

pub fn op_newline() -> Vec<u8> {
    op_0(0x0b)
}

pub fn quit() -> Vec<u8> {
    op_0(0x0a)
}

/// op-codes with 0 operators
/// $b0 -- $bf  short     0OP
pub fn op_0(value: u8) -> Vec<u8> {
    let byte = value | 0xb0;
    vec![byte]
}

/// op-codes with variable operators (4 are possible)
/// $e0 -- $ff  variable  VAR     (operand types in next byte(s))
pub fn op_var(value: u8, arg_types: Vec<ArgType>) -> Vec<u8> {
	let mut ret = Vec::new();
	ret.push(value | 0xe0);
    ret.push(encode_variable_arguments(arg_types));
    ret
}

/// op-codes with 1 operator
/// $80 -- $8f  short     1OP     large constant
/// $90 -- $9f  short     1OP     small constant
/// $a0 -- $af  short     1OP     variable
pub fn op_1( value: u8, arg_type: ArgType) -> Vec<u8> {
    let byte: u8 = match arg_type {
        ArgType::Reference  => 0x90 | value,  // same as SmallConst
        ArgType::Variable   => 0xa0 | value,
        ArgType::SmallConst => 0x90 | value,
        ArgType::LargeConst => 0x80 | value,
        _                   => panic!("no possible 1OP")
    };

    vec![byte]
}

/// $00 -- $1f  long      2OP     small constant, small constant
/// $20 -- $3f  long      2OP     small constant, variable
/// $40 -- $5f  long      2OP     variable, small constant
/// $60 -- $7f  long      2OP     variable, variable
///
/// $c0 -- $df  variable  2OP     (operand types in next byte)
/// not handled here: $be  extended opcode given in next byte
pub fn op_2( value: u8, arg_types: Vec<ArgType>) -> Vec<u8> {
    let mut byte: u8 = 0x00;
    let mut is_variable: bool = false;
    let mut ret = Vec::new();
    for (i, arg_type) in arg_types.iter().enumerate() {
        let shift: u8 = 6 - i as u8;
        match arg_type {
            &ArgType::SmallConst => byte |= 0x00 << shift,
            &ArgType::Variable   => byte |= 0x01 << shift,
            &ArgType::Reference  => byte |= 0x00 << shift,
            &ArgType::LargeConst => is_variable = true,
            _                    => panic!("no possible 2OP")
        }
    }

    if is_variable {
        let mut byte: u8 = 0xc0 | value;
        byte = byte | value;
        ret.push(byte);

        let mut byte2 = encode_variable_arguments(arg_types);
        byte2 = byte2 | 0xf;
        ret.push(byte2)
    } else {
        byte = byte | value;
        ret.push(byte)
    }
    ret
}

pub fn encode_variable_arguments( arg_types: Vec<ArgType>) -> u8 {
    let mut byte: u8 = 0x00;
    for (i, arg_type) in arg_types.iter().enumerate() {
        let shift: u8 = 6 - 2 * i as u8;
        match arg_type {
            &ArgType::LargeConst => byte |= 0x00 << shift,
            &ArgType::SmallConst => byte |= 0x01 << shift,
            &ArgType::Variable   => byte |= 0x02 << shift,
            &ArgType::Nothing    => byte |= 0x03 << shift,
            &ArgType::Reference  => byte |= 0x01 << shift,
            //_                    => panic!("no possible varOP")
        }
    }

    byte
 }

pub fn arg_type(operand: &Operand) -> ArgType {
    match operand {
        &Operand::Var(_) => ArgType::Variable,
        &Operand::Const(_) => ArgType::SmallConst,
        &Operand::LargeConst(_) => ArgType::LargeConst
    }
}

pub fn write_argument(operand: &Operand, v: &mut Vec<u8>){
    match operand {
        &Operand::Var(ref var)=> v.push(var.id),
        &Operand::Const(ref constant) => v.push(constant.value),
        &Operand::LargeConst(ref constant) => write_i16(constant.value, v)
    };
}

///writes u16 to a vec<u8>
pub fn write_u16(value: u16, v: &mut Vec<u8>) {
        v.push((value >> 8) as u8);
        v.push((value & 0xff) as u8);
}

///writes u16 to a vec<u8>
pub fn write_i16(value: i16, v: &mut Vec<u8>) {
        v.push((value >> 8) as u8);
        v.push((value & 0xff) as u8);
}
<|endoftext|>


<commit_before>//! Provides a way to attach fixes to the diagnostics.
//! The same module also has all curret custom fixes for the diagnostics implemented.
use ast::MethodCallExpr;
use hir::{
    db::AstDatabase,
    diagnostics::{
        Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField,
        RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnresolvedModule,
    },
    HasSource, HirDisplay, InFile, Semantics, VariantDef,
};
use ide_db::{
    base_db::{AnchoredPathBuf, FileId},
    source_change::{FileSystemEdit, SourceChange},
    RootDatabase,
};
use syntax::{AstNode, TextRange, algo, ast::{self, ArgList, edit::IndentLevel, make}};
use text_edit::TextEdit;

use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition};

/// A [Diagnostic] that potentially has a fix available.
///
/// [Diagnostic]: hir::diagnostics::Diagnostic
pub(crate) trait DiagnosticWithFix: Diagnostic {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
}

impl DiagnosticWithFix for UnresolvedModule {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let unresolved_module = self.decl.to_node(&root);
        Some(Fix::new(
            "Create module",
            FileSystemEdit::CreateFile {
                dst: AnchoredPathBuf {
                    anchor: self.file.original_file(sema.db),
                    path: self.candidate.clone(),
                },
                initial_contents: "".to_string(),
            }
            .into(),
            unresolved_module.syntax().text_range(),
        ))
    }
}

impl DiagnosticWithFix for NoSuchField {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        missing_record_expr_field_fix(
            &sema,
            self.file.original_file(sema.db),
            &self.field.to_node(&root),
        )
    }
}

impl DiagnosticWithFix for MissingFields {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        // Note that although we could add a diagnostics to
        // fill the missing tuple field, e.g :
        // `struct A(usize);`
        // `let a = A { 0: () }`
        // but it is uncommon usage and it should not be encouraged.
        if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
            return None;
        }

        let root = sema.db.parse_or_expand(self.file)?;
        let field_list_parent = self.field_list_parent.to_node(&root);
        let old_field_list = field_list_parent.record_expr_field_list()?;
        let mut new_field_list = old_field_list.clone();
        for f in self.missed_fields.iter() {
            let field =
                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
            new_field_list = new_field_list.append_field(&field);
        }

        let edit = {
            let mut builder = TextEdit::builder();
            algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
                .into_text_edit(&mut builder);
            builder.finish()
        };
        Some(Fix::new(
            "Fill struct fields",
            SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
            sema.original_range(&field_list_parent.syntax()).range,
        ))
    }
}

impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let tail_expr = self.expr.to_node(&root);
        let tail_expr_range = tail_expr.syntax().text_range();
        let replacement = format!("{}({})", self.required, tail_expr.syntax());
        let edit = TextEdit::replace(tail_expr_range, replacement);
        let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
        let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
        Some(Fix::new(name, source_change, tail_expr_range))
    }
}

impl DiagnosticWithFix for RemoveThisSemicolon {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;

        let semicolon = self
            .expr
            .to_node(&root)
            .syntax()
            .parent()
            .and_then(ast::ExprStmt::cast)
            .and_then(|expr| expr.semicolon_token())?
            .text_range();

        let edit = TextEdit::delete(semicolon);
        let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);

        Some(Fix::new("Remove this semicolon", source_change, semicolon))
    }
}

impl DiagnosticWithFix for IncorrectCase {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let name_node = self.ident.to_node(&root);

        let name_node = InFile::new(self.file, name_node.syntax());
        let frange = name_node.original_file_range(sema.db);
        let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };

        let rename_changes =
            rename_with_semantics(sema, file_position, &self.suggested_text).ok()?;

        let label = format!("Rename to {}", self.suggested_text);
        Some(Fix::new(&label, rename_changes, frange.range))
    }
}

impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let next_expr = self.next_expr.to_node(&root);
        let next_call = MethodCallExpr::cast(next_expr.syntax().clone())?;

        let filter_map_call = MethodCallExpr::cast(next_call.receiver()?.syntax().clone())?;
        let filter_map_name_range = filter_map_call.name_ref()?.ident_token()?.text_range();
        let filter_map_args = filter_map_call.syntax().children().find_map(ArgList::cast)?;

        let range_to_replace = TextRange::new(filter_map_name_range.start(), next_expr.syntax().text_range().end());
        let replacement = format!("find_map{}", filter_map_args.syntax().text());
        let trigger_range = next_expr.syntax().text_range();

        let edit = TextEdit::replace(range_to_replace, replacement);

        let source_change =
            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();

        Some(Fix::new(
            "Replace filter_map(..).next() with find_map()",
            source_change,
            trigger_range,
        ))
    }
}

fn missing_record_expr_field_fix(
    sema: &Semantics<RootDatabase>,
    usage_file_id: FileId,
    record_expr_field: &ast::RecordExprField,
) -> Option<Fix> {
    let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
    let def_id = sema.resolve_variant(record_lit)?;
    let module;
    let def_file_id;
    let record_fields = match VariantDef::from(def_id) {
        VariantDef::Struct(s) => {
            module = s.module(sema.db);
            let source = s.source(sema.db)?;
            def_file_id = source.file_id;
            let fields = source.value.field_list()?;
            record_field_list(fields)?
        }
        VariantDef::Union(u) => {
            module = u.module(sema.db);
            let source = u.source(sema.db)?;
            def_file_id = source.file_id;
            source.value.record_field_list()?
        }
        VariantDef::Variant(e) => {
            module = e.module(sema.db);
            let source = e.source(sema.db)?;
            def_file_id = source.file_id;
            let fields = source.value.field_list()?;
            record_field_list(fields)?
        }
    };
    let def_file_id = def_file_id.original_file(sema.db);

    let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
    if new_field_type.is_unknown() {
        return None;
    }
    let new_field = make::record_field(
        None,
        make::name(record_expr_field.field_name()?.text()),
        make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
    );

    let last_field = record_fields.fields().last()?;
    let last_field_syntax = last_field.syntax();
    let indent = IndentLevel::from_node(last_field_syntax);

    let mut new_field = new_field.to_string();
    if usage_file_id != def_file_id {
        new_field = format!("pub(crate) {}", new_field);
    }
    new_field = format!("\n{}{}", indent, new_field);

    let needs_comma = !last_field_syntax.to_string().ends_with(',');
    if needs_comma {
        new_field = format!(",{}", new_field);
    }

    let source_change = SourceChange::from_text_edit(
        def_file_id,
        TextEdit::insert(last_field_syntax.text_range().end(), new_field),
    );
    return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range()));

    fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
        match field_def_list {
            ast::FieldList::RecordFieldList(it) => Some(it),
            ast::FieldList::TupleFieldList(_) => None,
        }
    }
}
<commit_msg>cargo fmt<commit_after>//! Provides a way to attach fixes to the diagnostics.
//! The same module also has all curret custom fixes for the diagnostics implemented.
use ast::MethodCallExpr;
use hir::{
    db::AstDatabase,
    diagnostics::{
        Diagnostic, IncorrectCase, MissingFields, MissingOkOrSomeInTailExpr, NoSuchField,
        RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnresolvedModule,
    },
    HasSource, HirDisplay, InFile, Semantics, VariantDef,
};
use ide_db::{
    base_db::{AnchoredPathBuf, FileId},
    source_change::{FileSystemEdit, SourceChange},
    RootDatabase,
};
use syntax::{
    algo,
    ast::{self, edit::IndentLevel, make, ArgList},
    AstNode, TextRange,
};
use text_edit::TextEdit;

use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition};

/// A [Diagnostic] that potentially has a fix available.
///
/// [Diagnostic]: hir::diagnostics::Diagnostic
pub(crate) trait DiagnosticWithFix: Diagnostic {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>;
}

impl DiagnosticWithFix for UnresolvedModule {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let unresolved_module = self.decl.to_node(&root);
        Some(Fix::new(
            "Create module",
            FileSystemEdit::CreateFile {
                dst: AnchoredPathBuf {
                    anchor: self.file.original_file(sema.db),
                    path: self.candidate.clone(),
                },
                initial_contents: "".to_string(),
            }
            .into(),
            unresolved_module.syntax().text_range(),
        ))
    }
}

impl DiagnosticWithFix for NoSuchField {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        missing_record_expr_field_fix(
            &sema,
            self.file.original_file(sema.db),
            &self.field.to_node(&root),
        )
    }
}

impl DiagnosticWithFix for MissingFields {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        // Note that although we could add a diagnostics to
        // fill the missing tuple field, e.g :
        // `struct A(usize);`
        // `let a = A { 0: () }`
        // but it is uncommon usage and it should not be encouraged.
        if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) {
            return None;
        }

        let root = sema.db.parse_or_expand(self.file)?;
        let field_list_parent = self.field_list_parent.to_node(&root);
        let old_field_list = field_list_parent.record_expr_field_list()?;
        let mut new_field_list = old_field_list.clone();
        for f in self.missed_fields.iter() {
            let field =
                make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()));
            new_field_list = new_field_list.append_field(&field);
        }

        let edit = {
            let mut builder = TextEdit::builder();
            algo::diff(&old_field_list.syntax(), &new_field_list.syntax())
                .into_text_edit(&mut builder);
            builder.finish()
        };
        Some(Fix::new(
            "Fill struct fields",
            SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
            sema.original_range(&field_list_parent.syntax()).range,
        ))
    }
}

impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let tail_expr = self.expr.to_node(&root);
        let tail_expr_range = tail_expr.syntax().text_range();
        let replacement = format!("{}({})", self.required, tail_expr.syntax());
        let edit = TextEdit::replace(tail_expr_range, replacement);
        let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
        let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
        Some(Fix::new(name, source_change, tail_expr_range))
    }
}

impl DiagnosticWithFix for RemoveThisSemicolon {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;

        let semicolon = self
            .expr
            .to_node(&root)
            .syntax()
            .parent()
            .and_then(ast::ExprStmt::cast)
            .and_then(|expr| expr.semicolon_token())?
            .text_range();

        let edit = TextEdit::delete(semicolon);
        let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);

        Some(Fix::new("Remove this semicolon", source_change, semicolon))
    }
}

impl DiagnosticWithFix for IncorrectCase {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let name_node = self.ident.to_node(&root);

        let name_node = InFile::new(self.file, name_node.syntax());
        let frange = name_node.original_file_range(sema.db);
        let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };

        let rename_changes =
            rename_with_semantics(sema, file_position, &self.suggested_text).ok()?;

        let label = format!("Rename to {}", self.suggested_text);
        Some(Fix::new(&label, rename_changes, frange.range))
    }
}

impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
    fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> {
        let root = sema.db.parse_or_expand(self.file)?;
        let next_expr = self.next_expr.to_node(&root);
        let next_call = MethodCallExpr::cast(next_expr.syntax().clone())?;

        let filter_map_call = MethodCallExpr::cast(next_call.receiver()?.syntax().clone())?;
        let filter_map_name_range = filter_map_call.name_ref()?.ident_token()?.text_range();
        let filter_map_args = filter_map_call.syntax().children().find_map(ArgList::cast)?;

        let range_to_replace =
            TextRange::new(filter_map_name_range.start(), next_expr.syntax().text_range().end());
        let replacement = format!("find_map{}", filter_map_args.syntax().text());
        let trigger_range = next_expr.syntax().text_range();

        let edit = TextEdit::replace(range_to_replace, replacement);

        let source_change =
            SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into();

        Some(Fix::new(
            "Replace filter_map(..).next() with find_map()",
            source_change,
            trigger_range,
        ))
    }
}

fn missing_record_expr_field_fix(
    sema: &Semantics<RootDatabase>,
    usage_file_id: FileId,
    record_expr_field: &ast::RecordExprField,
) -> Option<Fix> {
    let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
    let def_id = sema.resolve_variant(record_lit)?;
    let module;
    let def_file_id;
    let record_fields = match VariantDef::from(def_id) {
        VariantDef::Struct(s) => {
            module = s.module(sema.db);
            let source = s.source(sema.db)?;
            def_file_id = source.file_id;
            let fields = source.value.field_list()?;
            record_field_list(fields)?
        }
        VariantDef::Union(u) => {
            module = u.module(sema.db);
            let source = u.source(sema.db)?;
            def_file_id = source.file_id;
            source.value.record_field_list()?
        }
        VariantDef::Variant(e) => {
            module = e.module(sema.db);
            let source = e.source(sema.db)?;
            def_file_id = source.file_id;
            let fields = source.value.field_list()?;
            record_field_list(fields)?
        }
    };
    let def_file_id = def_file_id.original_file(sema.db);

    let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?;
    if new_field_type.is_unknown() {
        return None;
    }
    let new_field = make::record_field(
        None,
        make::name(record_expr_field.field_name()?.text()),
        make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
    );

    let last_field = record_fields.fields().last()?;
    let last_field_syntax = last_field.syntax();
    let indent = IndentLevel::from_node(last_field_syntax);

    let mut new_field = new_field.to_string();
    if usage_file_id != def_file_id {
        new_field = format!("pub(crate) {}", new_field);
    }
    new_field = format!("\n{}{}", indent, new_field);

    let needs_comma = !last_field_syntax.to_string().ends_with(',');
    if needs_comma {
        new_field = format!(",{}", new_field);
    }

    let source_change = SourceChange::from_text_edit(
        def_file_id,
        TextEdit::insert(last_field_syntax.text_range().end(), new_field),
    );
    return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range()));

    fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
        match field_def_list {
            ast::FieldList::RecordFieldList(it) => Some(it),
            ast::FieldList::TupleFieldList(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use relative_path::RelativePathBuf;
use ra_db::{CrateId, Cancelable, FileId};
use ra_syntax::{ast, TreeArc, SyntaxNode, AstNode};

use crate::{
    Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId,
    type_ref::TypeRef,
    nameres::ModuleScope,
    db::HirDatabase,
    expr::BodySyntaxMapping,
    ty::InferenceResult,
    adt::VariantData,
};

/// hir::Crate describes a single crate. It's the main interface with which
/// a crate's dependencies interact. Mostly, it should be just a proxy for the
/// root module.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Crate {
    pub(crate) crate_id: CrateId,
}

#[derive(Debug)]
pub struct CrateDependency {
    pub krate: Crate,
    pub name: Name,
}

impl Crate {
    pub fn crate_id(&self) -> CrateId {
        self.crate_id
    }
    pub fn dependencies(&self, db: &impl HirDatabase) -> Cancelable<Vec<CrateDependency>> {
        Ok(self.dependencies_impl(db))
    }
    pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
        self.root_module_impl(db)
    }
}

pub enum Def {
    Module(Module),
    Struct(Struct),
    Enum(Enum),
    EnumVariant(EnumVariant),
    Function(Function),
    Item,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Module {
    pub(crate) def_id: DefId,
}

pub enum ModuleSource {
    SourceFile(TreeArc<ast::SourceFile>),
    Module(TreeArc<ast::Module>),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Problem {
    UnresolvedModule {
        candidate: RelativePathBuf,
    },
    NotDirOwner {
        move_to: RelativePathBuf,
        candidate: RelativePathBuf,
    },
}

impl Module {
    /// Name of this module.
    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        self.name_impl(db)
    }

    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(&self, db: &impl HirDatabase) -> Cancelable<(FileId, ModuleSource)> {
        self.definition_source_impl(db)
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<Option<(FileId, TreeArc<ast::Module>)>> {
        self.declaration_source_impl(db)
    }

    /// Returns the crate this module is part of.
    pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
        self.krate_impl(db)
    }

    /// Topmost parent of this module. Every module has a `crate_root`, but some
    /// might be missing `krate`. This can happen if a module's file is not included
    /// in the module tree of any target in Cargo.toml.
    pub fn crate_root(&self, db: &impl HirDatabase) -> Cancelable<Module> {
        self.crate_root_impl(db)
    }

    /// Finds a child module with the specified name.
    pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
        self.child_impl(db, name)
    }

    /// Finds a parent module.
    pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
        self.parent_impl(db)
    }

    pub fn path_to_root(&self, db: &impl HirDatabase) -> Cancelable<Vec<Module>> {
        let mut res = vec![self.clone()];
        let mut curr = self.clone();
        while let Some(next) = curr.parent(db)? {
            res.push(next.clone());
            curr = next
        }
        Ok(res)
    }

    /// Returns a `ModuleScope`: a set of items, visible in this module.
    pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
        self.scope_impl(db)
    }

    pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
        self.resolve_path_impl(db, path)
    }

    pub fn problems(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<Vec<(TreeArc<SyntaxNode>, Problem)>> {
        self.problems_impl(db)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructField {
    struct_: Struct,
    name: Name,
}

impl StructField {
    pub fn name(&self) -> &Name {
        &self.name
    }
    pub fn ty(&self, db: &impl HirDatabase) -> Cancelable<Option<Ty>> {
        db.type_for_field(self.struct_.def_id, self.name.clone())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Struct {
    pub(crate) def_id: DefId,
}

impl Struct {
    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.struct_data(self.def_id)?.name.clone())
    }

    pub fn fields(&self, db: &impl HirDatabase) -> Cancelable<Vec<StructField>> {
        let res = db
            .struct_data(self.def_id)?
            .variant_data
            .fields()
            .iter()
            .map(|it| StructField {
                struct_: self.clone(),
                name: it.name.clone(),
            })
            .collect();
        Ok(res)
    }

    pub fn source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<(HirFileId, TreeArc<ast::StructDef>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::StructDef::cast(&syntax)
                .expect("struct def should point to StructDef node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Enum {
    pub(crate) def_id: DefId,
}

impl Enum {
    pub(crate) fn new(def_id: DefId) -> Self {
        Enum { def_id }
    }

    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.enum_data(self.def_id)?.name.clone())
    }

    pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, EnumVariant)>> {
        Ok(db.enum_data(self.def_id)?.variants.clone())
    }

    pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreeArc<ast::EnumDef>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::EnumDef::cast(&syntax)
                .expect("enum def should point to EnumDef node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumVariant {
    pub(crate) def_id: DefId,
}

impl EnumVariant {
    pub(crate) fn new(def_id: DefId) -> Self {
        EnumVariant { def_id }
    }

    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn parent_enum(&self, db: &impl HirDatabase) -> Cancelable<Enum> {
        Ok(db.enum_variant_data(self.def_id)?.parent_enum.clone())
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.enum_variant_data(self.def_id)?.name.clone())
    }

    pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
        Ok(db.enum_variant_data(self.def_id)?.variant_data.clone())
    }

    pub fn source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<(HirFileId, TreeArc<ast::EnumVariant>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::EnumVariant::cast(&syntax)
                .expect("variant def should point to EnumVariant node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Function {
    pub(crate) def_id: DefId,
}

pub use crate::code_model_impl::function::ScopeEntryWithSyntax;

/// The declared signature of a function.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FnSignature {
    pub(crate) name: Name,
    pub(crate) args: Vec<TypeRef>,
    pub(crate) ret_type: TypeRef,
}

impl FnSignature {
    pub fn name(&self) -> &Name {
        &self.name
    }

    pub fn args(&self) -> &[TypeRef] {
        &self.args
    }

    pub fn ret_type(&self) -> &TypeRef {
        &self.ret_type
    }
}

impl Function {
    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreeArc<ast::FnDef>)> {
        Ok(self.source_impl(db))
    }

    pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> {
        db.body_syntax_mapping(self.def_id)
    }

    pub fn scopes(&self, db: &impl HirDatabase) -> Cancelable<ScopesWithSyntaxMapping> {
        let scopes = db.fn_scopes(self.def_id)?;
        let syntax_mapping = db.body_syntax_mapping(self.def_id)?;
        Ok(ScopesWithSyntaxMapping {
            scopes,
            syntax_mapping,
        })
    }

    pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
        db.fn_signature(self.def_id)
    }

    pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
        db.infer(self.def_id)
    }
}
<commit_msg>add missing def kinds<commit_after>use std::sync::Arc;

use relative_path::RelativePathBuf;
use ra_db::{CrateId, Cancelable, FileId};
use ra_syntax::{ast, TreeArc, SyntaxNode, AstNode};

use crate::{
    Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId,
    type_ref::TypeRef,
    nameres::ModuleScope,
    db::HirDatabase,
    expr::BodySyntaxMapping,
    ty::InferenceResult,
    adt::VariantData,
};

/// hir::Crate describes a single crate. It's the main interface with which
/// a crate's dependencies interact. Mostly, it should be just a proxy for the
/// root module.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Crate {
    pub(crate) crate_id: CrateId,
}

#[derive(Debug)]
pub struct CrateDependency {
    pub krate: Crate,
    pub name: Name,
}

impl Crate {
    pub fn crate_id(&self) -> CrateId {
        self.crate_id
    }
    pub fn dependencies(&self, db: &impl HirDatabase) -> Cancelable<Vec<CrateDependency>> {
        Ok(self.dependencies_impl(db))
    }
    pub fn root_module(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
        self.root_module_impl(db)
    }
}

pub enum Def {
    Module(Module),
    Struct(Struct),
    Enum(Enum),
    EnumVariant(EnumVariant),
    Function(Function),
    Item,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Module {
    pub(crate) def_id: DefId,
}

pub enum ModuleSource {
    SourceFile(TreeArc<ast::SourceFile>),
    Module(TreeArc<ast::Module>),
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Problem {
    UnresolvedModule {
        candidate: RelativePathBuf,
    },
    NotDirOwner {
        move_to: RelativePathBuf,
        candidate: RelativePathBuf,
    },
}

impl Module {
    /// Name of this module.
    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        self.name_impl(db)
    }

    /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
    pub fn definition_source(&self, db: &impl HirDatabase) -> Cancelable<(FileId, ModuleSource)> {
        self.definition_source_impl(db)
    }

    /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
    /// `None` for the crate root.
    pub fn declaration_source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<Option<(FileId, TreeArc<ast::Module>)>> {
        self.declaration_source_impl(db)
    }

    /// Returns the crate this module is part of.
    pub fn krate(&self, db: &impl HirDatabase) -> Cancelable<Option<Crate>> {
        self.krate_impl(db)
    }

    /// Topmost parent of this module. Every module has a `crate_root`, but some
    /// might be missing `krate`. This can happen if a module's file is not included
    /// in the module tree of any target in Cargo.toml.
    pub fn crate_root(&self, db: &impl HirDatabase) -> Cancelable<Module> {
        self.crate_root_impl(db)
    }

    /// Finds a child module with the specified name.
    pub fn child(&self, db: &impl HirDatabase, name: &Name) -> Cancelable<Option<Module>> {
        self.child_impl(db, name)
    }

    /// Finds a parent module.
    pub fn parent(&self, db: &impl HirDatabase) -> Cancelable<Option<Module>> {
        self.parent_impl(db)
    }

    pub fn path_to_root(&self, db: &impl HirDatabase) -> Cancelable<Vec<Module>> {
        let mut res = vec![self.clone()];
        let mut curr = self.clone();
        while let Some(next) = curr.parent(db)? {
            res.push(next.clone());
            curr = next
        }
        Ok(res)
    }

    /// Returns a `ModuleScope`: a set of items, visible in this module.
    pub fn scope(&self, db: &impl HirDatabase) -> Cancelable<ModuleScope> {
        self.scope_impl(db)
    }

    pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> Cancelable<PerNs<DefId>> {
        self.resolve_path_impl(db, path)
    }

    pub fn problems(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<Vec<(TreeArc<SyntaxNode>, Problem)>> {
        self.problems_impl(db)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructField {
    struct_: Struct,
    name: Name,
}

impl StructField {
    pub fn name(&self) -> &Name {
        &self.name
    }
    pub fn ty(&self, db: &impl HirDatabase) -> Cancelable<Option<Ty>> {
        db.type_for_field(self.struct_.def_id, self.name.clone())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Struct {
    pub(crate) def_id: DefId,
}

impl Struct {
    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.struct_data(self.def_id)?.name.clone())
    }

    pub fn fields(&self, db: &impl HirDatabase) -> Cancelable<Vec<StructField>> {
        let res = db
            .struct_data(self.def_id)?
            .variant_data
            .fields()
            .iter()
            .map(|it| StructField {
                struct_: self.clone(),
                name: it.name.clone(),
            })
            .collect();
        Ok(res)
    }

    pub fn source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<(HirFileId, TreeArc<ast::StructDef>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::StructDef::cast(&syntax)
                .expect("struct def should point to StructDef node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Enum {
    pub(crate) def_id: DefId,
}

impl Enum {
    pub(crate) fn new(def_id: DefId) -> Self {
        Enum { def_id }
    }

    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.enum_data(self.def_id)?.name.clone())
    }

    pub fn variants(&self, db: &impl HirDatabase) -> Cancelable<Vec<(Name, EnumVariant)>> {
        Ok(db.enum_data(self.def_id)?.variants.clone())
    }

    pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreeArc<ast::EnumDef>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::EnumDef::cast(&syntax)
                .expect("enum def should point to EnumDef node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumVariant {
    pub(crate) def_id: DefId,
}

impl EnumVariant {
    pub(crate) fn new(def_id: DefId) -> Self {
        EnumVariant { def_id }
    }

    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn parent_enum(&self, db: &impl HirDatabase) -> Cancelable<Enum> {
        Ok(db.enum_variant_data(self.def_id)?.parent_enum.clone())
    }

    pub fn name(&self, db: &impl HirDatabase) -> Cancelable<Option<Name>> {
        Ok(db.enum_variant_data(self.def_id)?.name.clone())
    }

    pub fn variant_data(&self, db: &impl HirDatabase) -> Cancelable<Arc<VariantData>> {
        Ok(db.enum_variant_data(self.def_id)?.variant_data.clone())
    }

    pub fn source(
        &self,
        db: &impl HirDatabase,
    ) -> Cancelable<(HirFileId, TreeArc<ast::EnumVariant>)> {
        let (file_id, syntax) = self.def_id.source(db);
        Ok((
            file_id,
            ast::EnumVariant::cast(&syntax)
                .expect("variant def should point to EnumVariant node")
                .to_owned(),
        ))
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Function {
    pub(crate) def_id: DefId,
}

pub use crate::code_model_impl::function::ScopeEntryWithSyntax;

/// The declared signature of a function.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FnSignature {
    pub(crate) name: Name,
    pub(crate) args: Vec<TypeRef>,
    pub(crate) ret_type: TypeRef,
}

impl FnSignature {
    pub fn name(&self) -> &Name {
        &self.name
    }

    pub fn args(&self) -> &[TypeRef] {
        &self.args
    }

    pub fn ret_type(&self) -> &TypeRef {
        &self.ret_type
    }
}

impl Function {
    pub fn def_id(&self) -> DefId {
        self.def_id
    }

    pub fn source(&self, db: &impl HirDatabase) -> Cancelable<(HirFileId, TreeArc<ast::FnDef>)> {
        Ok(self.source_impl(db))
    }

    pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> {
        db.body_syntax_mapping(self.def_id)
    }

    pub fn scopes(&self, db: &impl HirDatabase) -> Cancelable<ScopesWithSyntaxMapping> {
        let scopes = db.fn_scopes(self.def_id)?;
        let syntax_mapping = db.body_syntax_mapping(self.def_id)?;
        Ok(ScopesWithSyntaxMapping {
            scopes,
            syntax_mapping,
        })
    }

    pub fn signature(&self, db: &impl HirDatabase) -> Arc<FnSignature> {
        db.fn_signature(self.def_id)
    }

    pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
        db.infer(self.def_id)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Const {
    pub(crate) def_id: DefId,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Static {
    pub(crate) def_id: DefId,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Trait {
    pub(crate) def_id: DefId,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Type {
    pub(crate) def_id: DefId,
}
<|endoftext|>


<commit_before>//! Handle process life-time and message passing for proc-macro client

use crossbeam_channel::{bounded, Receiver, Sender};
use ra_tt::Subtree;

use crate::msg::{ErrorCode, Message, Request, Response, ResponseError};
use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};

use io::{BufRead, BufReader};
use std::{
    convert::{TryFrom, TryInto},
    io::{self, Write},
    path::{Path, PathBuf},
    process::{Child, Command, Stdio},
    sync::{Arc, Weak},
};

#[derive(Debug, Default)]
pub(crate) struct ProcMacroProcessSrv {
    inner: Option<Weak<Sender<Task>>>,
}

#[derive(Debug)]
pub(crate) struct ProcMacroProcessThread {
    // XXX: drop order is significant
    sender: Arc<Sender<Task>>,
    handle: jod_thread::JoinHandle<()>,
}

struct Task {
    req: Request,
    result_tx: Sender<Option<Response>>,
}

struct Process {
    path: PathBuf,
    child: Child,
}

impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

impl Process {
    fn run(process_path: &Path) -> Result<Process, io::Error> {
        let child = Command::new(process_path.clone())
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?;

        Ok(Process { path: process_path.into(), child })
    }

    fn restart(&mut self) -> Result<(), io::Error> {
        let _ = self.child.kill();
        self.child =
            Command::new(self.path.clone()).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
        Ok(())
    }

    fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
        let stdin = self.child.stdin.take()?;
        let stdout = self.child.stdout.take()?;
        let read = BufReader::new(stdout);

        Some((stdin, read))
    }
}

impl ProcMacroProcessSrv {
    pub fn run(
        process_path: &Path,
    ) -> Result<(ProcMacroProcessThread, ProcMacroProcessSrv), io::Error> {
        let process = Process::run(process_path)?;

        let (task_tx, task_rx) = bounded(0);
        let handle = jod_thread::spawn(move || {
            client_loop(task_rx, process);
        });

        let task_tx = Arc::new(task_tx);
        let srv = ProcMacroProcessSrv { inner: Some(Arc::downgrade(&task_tx)) };
        let thread = ProcMacroProcessThread { handle, sender: task_tx };

        Ok((thread, srv))
    }

    pub fn find_proc_macros(
        &self,
        dylib_path: &Path,
    ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> {
        let task = ListMacrosTask { lib: dylib_path.to_path_buf() };

        let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
        Ok(result.macros)
    }

    pub fn custom_derive(
        &self,
        dylib_path: &Path,
        subtree: &Subtree,
        derive_name: &str,
    ) -> Result<Subtree, ra_tt::ExpansionError> {
        let task = ExpansionTask {
            macro_body: subtree.clone(),
            macro_name: derive_name.to_string(),
            attributes: None,
            lib: dylib_path.to_path_buf(),
        };

        let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
        Ok(result.expansion)
    }

    pub fn send_task<R>(&self, req: Request) -> Result<R, ra_tt::ExpansionError>
    where
        R: TryFrom<Response, Error = &'static str>,
    {
        let sender = match &self.inner {
            None => return Err(ra_tt::ExpansionError::Unknown("No sender is found.".to_string())),
            Some(it) => it,
        };

        let (result_tx, result_rx) = bounded(0);
        let sender = match sender.upgrade() {
            None => {
                return Err(ra_tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
            }
            Some(it) => it,
        };
        sender.send(Task { req: req.into(), result_tx }).unwrap();
        let res = result_rx
            .recv()
            .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;

        match res {
            Some(Response::Error(err)) => {
                return Err(ra_tt::ExpansionError::ExpansionError(err.message));
            }
            Some(res) => Ok(res.try_into().map_err(|err| {
                ra_tt::ExpansionError::Unknown(format!(
                    "Fail to get response, reason : {:#?} ",
                    err
                ))
            })?),
            None => Err(ra_tt::ExpansionError::Unknown("Empty result".into())),
        }
    }
}

fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
    let (mut stdin, mut stdout) = match process.stdio() {
        None => return,
        Some(it) => it,
    };

    for task in task_rx {
        let Task { req, result_tx } = task;

        match send_request(&mut stdin, &mut stdout, req) {
            Ok(res) => result_tx.send(res).unwrap(),
            Err(_err) => {
                let res = Response::Error(ResponseError {
                    code: ErrorCode::ServerErrorEnd,
                    message: "Server closed".into(),
                });
                result_tx.send(res.into()).unwrap();
                // Restart the process
                if process.restart().is_err() {
                    break;
                }
                let stdio = match process.stdio() {
                    None => break,
                    Some(it) => it,
                };
                stdin = stdio.0;
                stdout = stdio.1;
            }
        }
    }
}

fn send_request(
    mut writer: &mut impl Write,
    mut reader: &mut impl BufRead,
    req: Request,
) -> Result<Option<Response>, io::Error> {
    req.write(&mut writer)?;
    Ok(Response::read(&mut reader)?)
}
<commit_msg>Pipe error to stderr<commit_after>//! Handle process life-time and message passing for proc-macro client

use crossbeam_channel::{bounded, Receiver, Sender};
use ra_tt::Subtree;

use crate::msg::{ErrorCode, Message, Request, Response, ResponseError};
use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};

use io::{BufRead, BufReader};
use std::{
    convert::{TryFrom, TryInto},
    io::{self, Write},
    path::{Path, PathBuf},
    process::{Child, Command, Stdio},
    sync::{Arc, Weak},
};

#[derive(Debug, Default)]
pub(crate) struct ProcMacroProcessSrv {
    inner: Option<Weak<Sender<Task>>>,
}

#[derive(Debug)]
pub(crate) struct ProcMacroProcessThread {
    // XXX: drop order is significant
    sender: Arc<Sender<Task>>,
    handle: jod_thread::JoinHandle<()>,
}

struct Task {
    req: Request,
    result_tx: Sender<Option<Response>>,
}

struct Process {
    path: PathBuf,
    child: Child,
}

impl Drop for Process {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

impl Process {
    fn run(process_path: &Path) -> Result<Process, io::Error> {
        let child = Command::new(process_path.clone())
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?;

        Ok(Process { path: process_path.into(), child })
    }

    fn restart(&mut self) -> Result<(), io::Error> {
        let _ = self.child.kill();
        self.child = Command::new(self.path.clone())
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::null())
            .spawn()?;
        Ok(())
    }

    fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
        let stdin = self.child.stdin.take()?;
        let stdout = self.child.stdout.take()?;
        let read = BufReader::new(stdout);

        Some((stdin, read))
    }
}

impl ProcMacroProcessSrv {
    pub fn run(
        process_path: &Path,
    ) -> Result<(ProcMacroProcessThread, ProcMacroProcessSrv), io::Error> {
        let process = Process::run(process_path)?;

        let (task_tx, task_rx) = bounded(0);
        let handle = jod_thread::spawn(move || {
            client_loop(task_rx, process);
        });

        let task_tx = Arc::new(task_tx);
        let srv = ProcMacroProcessSrv { inner: Some(Arc::downgrade(&task_tx)) };
        let thread = ProcMacroProcessThread { handle, sender: task_tx };

        Ok((thread, srv))
    }

    pub fn find_proc_macros(
        &self,
        dylib_path: &Path,
    ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> {
        let task = ListMacrosTask { lib: dylib_path.to_path_buf() };

        let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
        Ok(result.macros)
    }

    pub fn custom_derive(
        &self,
        dylib_path: &Path,
        subtree: &Subtree,
        derive_name: &str,
    ) -> Result<Subtree, ra_tt::ExpansionError> {
        let task = ExpansionTask {
            macro_body: subtree.clone(),
            macro_name: derive_name.to_string(),
            attributes: None,
            lib: dylib_path.to_path_buf(),
        };

        let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
        Ok(result.expansion)
    }

    pub fn send_task<R>(&self, req: Request) -> Result<R, ra_tt::ExpansionError>
    where
        R: TryFrom<Response, Error = &'static str>,
    {
        let sender = match &self.inner {
            None => return Err(ra_tt::ExpansionError::Unknown("No sender is found.".to_string())),
            Some(it) => it,
        };

        let (result_tx, result_rx) = bounded(0);
        let sender = match sender.upgrade() {
            None => {
                return Err(ra_tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
            }
            Some(it) => it,
        };
        sender.send(Task { req: req.into(), result_tx }).unwrap();
        let res = result_rx
            .recv()
            .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;

        match res {
            Some(Response::Error(err)) => {
                return Err(ra_tt::ExpansionError::ExpansionError(err.message));
            }
            Some(res) => Ok(res.try_into().map_err(|err| {
                ra_tt::ExpansionError::Unknown(format!(
                    "Fail to get response, reason : {:#?} ",
                    err
                ))
            })?),
            None => Err(ra_tt::ExpansionError::Unknown("Empty result".into())),
        }
    }
}

fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
    let (mut stdin, mut stdout) = match process.stdio() {
        None => return,
        Some(it) => it,
    };

    for task in task_rx {
        let Task { req, result_tx } = task;

        match send_request(&mut stdin, &mut stdout, req) {
            Ok(res) => result_tx.send(res).unwrap(),
            Err(_err) => {
                let res = Response::Error(ResponseError {
                    code: ErrorCode::ServerErrorEnd,
                    message: "Server closed".into(),
                });
                result_tx.send(res.into()).unwrap();
                // Restart the process
                if process.restart().is_err() {
                    break;
                }
                let stdio = match process.stdio() {
                    None => break,
                    Some(it) => it,
                };
                stdin = stdio.0;
                stdout = stdio.1;
            }
        }
    }
}

fn send_request(
    mut writer: &mut impl Write,
    mut reader: &mut impl BufRead,
    req: Request,
) -> Result<Option<Response>, io::Error> {
    req.write(&mut writer)?;
    Ok(Response::read(&mut reader)?)
}
<|endoftext|>


<commit_before>use std::{
    clone::Clone,
    fmt::{self, Debug},
    marker::PhantomData,
    mem,
};

use serde::{
    de::{self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, MapAccess, Visitor},
    ser::{Serialize, Serializer},
};
use serde_json::value::{to_raw_value as to_raw_json_value, RawValue as RawJsonValue};

/// A wrapper around `Box<RawValue>`, to be used in place of any type in the Matrix endpoint
/// definition to allow request and response types to contain that said type represented by
/// the generic argument `Ev`.
///
/// Ruma offers the `Raw` wrapper to enable passing around JSON text that is only partially
/// validated. This is useful when a client receives events that do not follow the spec perfectly
/// or a server needs to generate reference hashes with the original canonical JSON string.
/// All event structs and enums implement `Serialize` / `Deserialize`, `Raw` should be used
/// to pass around events in a lossless way.
///
/// ```no_run
/// # use serde::Deserialize;
/// # use ruma_common::serde::Raw;
/// # #[derive(Deserialize)]
/// # struct AnyRoomEvent;
///
/// let json = r#"{ "type": "imagine a full event", "content": {...} }"#;
///
/// let deser = serde_json::from_str::<Raw<AnyRoomEvent>>(json)
///     .unwrap() // the first Result from serde_json::from_str, will not fail
///     .deserialize() // deserialize to the inner type
///     .unwrap(); // finally get to the AnyRoomEvent
/// ```
#[repr(transparent)]
pub struct Raw<T> {
    json: Box<RawJsonValue>,
    _ev: PhantomData<T>,
}

impl<T> Raw<T> {
    /// Create a `Raw` by serializing the given `T`.
    ///
    /// Shorthand for `serde_json::value::to_raw_value(val).map(Raw::from_json)`, but specialized to
    /// `T`.
    ///
    /// # Errors
    ///
    /// Fails if `T`s [`Serialize`] implementation fails.
    pub fn new(val: &T) -> serde_json::Result<Self>
    where
        T: Serialize,
    {
        to_raw_json_value(val).map(Self::from_json)
    }

    /// Create a `Raw` from a boxed `RawValue`.
    pub fn from_json(json: Box<RawJsonValue>) -> Self {
        Self { json, _ev: PhantomData }
    }

    /// Access the underlying json value.
    pub fn json(&self) -> &RawJsonValue {
        &self.json
    }

    /// Convert `self` into the underlying json value.
    pub fn into_json(self) -> Box<RawJsonValue> {
        self.json
    }

    /// Try to access a given field inside this `Raw`, assuming it contains an object.
    ///
    /// Returns `Err(_)` when the contained value is not an object, or the field exists but is fails
    /// to deserialize to the expected type.
    ///
    /// Returns `Ok(None)` when the field doesn't exist or is `null`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # type CustomMatrixEvent = ();
    /// # fn foo() -> serde_json::Result<()> {
    /// # let raw_event: ruma_common::serde::Raw<()> = todo!();
    /// if raw_event.get_field::<String>("type")?.as_deref() == Some("org.custom.matrix.event") {
    ///     let event = raw_event.deserialize_as::<CustomMatrixEvent>()?;
    ///     // ...
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn get_field<'a, U>(&'a self, field_name: &str) -> serde_json::Result<Option<U>>
    where
        U: Deserialize<'a>,
    {
        struct FieldVisitor<'b>(&'b str);

        impl<'b, 'de> Visitor<'de> for FieldVisitor<'b> {
            type Value = bool;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "`{}`", self.0)
            }

            fn visit_str<E>(self, value: &str) -> Result<bool, E>
            where
                E: de::Error,
            {
                Ok(value == self.0)
            }
        }

        struct Field<'b>(&'b str);

        impl<'b, 'de> DeserializeSeed<'de> for Field<'b> {
            type Value = bool;

            fn deserialize<D>(self, deserializer: D) -> Result<bool, D::Error>
            where
                D: Deserializer<'de>,
            {
                deserializer.deserialize_identifier(FieldVisitor(self.0))
            }
        }

        struct SingleFieldVisitor<'b, T> {
            field_name: &'b str,
            _phantom: PhantomData<T>,
        }

        impl<'b, T> SingleFieldVisitor<'b, T> {
            fn new(field_name: &'b str) -> Self {
                Self { field_name, _phantom: PhantomData }
            }
        }

        impl<'b, 'de, T> Visitor<'de> for SingleFieldVisitor<'b, T>
        where
            T: Deserialize<'de>,
        {
            type Value = Option<T>;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> std::fmt::Result {
                formatter.write_str("a string")
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: MapAccess<'de>,
            {
                let mut res = None;
                while let Some(is_right_field) = map.next_key_seed(Field(self.field_name))? {
                    if is_right_field {
                        res = Some(map.next_value()?);
                    } else {
                        map.next_value::<IgnoredAny>()?;
                    }
                }

                Ok(res)
            }
        }

        let mut deserializer = serde_json::Deserializer::from_str(self.json().get());
        deserializer.deserialize_map(SingleFieldVisitor::new(field_name))
    }

    /// Try to deserialize the JSON as the expected type.
    pub fn deserialize<'a>(&'a self) -> serde_json::Result<T>
    where
        T: Deserialize<'a>,
    {
        serde_json::from_str(self.json.get())
    }

    /// Try to deserialize the JSON as a custom type.
    pub fn deserialize_as<'a, U>(&'a self) -> serde_json::Result<U>
    where
        U: Deserialize<'a>,
    {
        serde_json::from_str(self.json.get())
    }

    /// Turns `Raw<T>` into `Raw<U>` without changing the underlying JSON.
    ///
    /// This is useful for turning raw specific event types into raw event enum types.
    pub fn cast<U>(self) -> Raw<U> {
        Raw::from_json(self.into_json())
    }

    /// Turns `&Raw<T>` into `&Raw<U>` without changing the underlying JSON.
    ///
    /// This is useful for turning raw specific event types into raw event enum types.
    pub fn cast_ref<U>(&self) -> &Raw<U> {
        unsafe { mem::transmute(self) }
    }
}

impl<T> Clone for Raw<T> {
    fn clone(&self) -> Self {
        Self::from_json(self.json.clone())
    }
}

impl<T> Debug for Raw<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::any::type_name;
        f.debug_struct(&format!("Raw::<{}>", type_name::<T>())).field("json", &self.json).finish()
    }
}

impl<'de, T> Deserialize<'de> for Raw<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Box::<RawJsonValue>::deserialize(deserializer).map(Self::from_json)
    }
}

impl<T> Serialize for Raw<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.json.serialize(serializer)
    }
}

#[cfg(test)]
mod tests {
    use serde::Deserialize;
    use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};

    use super::Raw;

    #[test]
    fn get_field() -> serde_json::Result<()> {
        #[derive(Debug, PartialEq, Deserialize)]
        struct A<'a> {
            #[serde(borrow)]
            b: Vec<&'a str>,
        }

        const OBJ: &str = r#"{ "a": { "b": [  "c"] }, "z": 5 }"#;
        let raw: Raw<()> = from_json_str(OBJ)?;

        assert_eq!(raw.get_field::<u8>("z")?, Some(5));
        assert_eq!(raw.get_field::<&RawJsonValue>("a")?.unwrap().get(), r#"{ "b": [  "c"] }"#);
        assert_eq!(raw.get_field::<A<'_>>("a")?, Some(A { b: vec!["c"] }));

        assert_eq!(raw.get_field::<u8>("b")?, None);
        raw.get_field::<u8>("a").unwrap_err();

        Ok(())
    }
}
<commit_msg>serde: Add Raw::from_json_string<commit_after>use std::{
    clone::Clone,
    fmt::{self, Debug},
    marker::PhantomData,
    mem,
};

use serde::{
    de::{self, Deserialize, DeserializeSeed, Deserializer, IgnoredAny, MapAccess, Visitor},
    ser::{Serialize, Serializer},
};
use serde_json::value::{to_raw_value as to_raw_json_value, RawValue as RawJsonValue};

/// A wrapper around `Box<RawValue>`, to be used in place of any type in the Matrix endpoint
/// definition to allow request and response types to contain that said type represented by
/// the generic argument `Ev`.
///
/// Ruma offers the `Raw` wrapper to enable passing around JSON text that is only partially
/// validated. This is useful when a client receives events that do not follow the spec perfectly
/// or a server needs to generate reference hashes with the original canonical JSON string.
/// All event structs and enums implement `Serialize` / `Deserialize`, `Raw` should be used
/// to pass around events in a lossless way.
///
/// ```no_run
/// # use serde::Deserialize;
/// # use ruma_common::serde::Raw;
/// # #[derive(Deserialize)]
/// # struct AnyRoomEvent;
///
/// let json = r#"{ "type": "imagine a full event", "content": {...} }"#;
///
/// let deser = serde_json::from_str::<Raw<AnyRoomEvent>>(json)
///     .unwrap() // the first Result from serde_json::from_str, will not fail
///     .deserialize() // deserialize to the inner type
///     .unwrap(); // finally get to the AnyRoomEvent
/// ```
#[repr(transparent)]
pub struct Raw<T> {
    json: Box<RawJsonValue>,
    _ev: PhantomData<T>,
}

impl<T> Raw<T> {
    /// Create a `Raw` by serializing the given `T`.
    ///
    /// Shorthand for `serde_json::value::to_raw_value(val).map(Raw::from_json)`, but specialized to
    /// `T`.
    ///
    /// # Errors
    ///
    /// Fails if `T`s [`Serialize`] implementation fails.
    pub fn new(val: &T) -> serde_json::Result<Self>
    where
        T: Serialize,
    {
        to_raw_json_value(val).map(Self::from_json)
    }

    /// Create a `Raw` from a boxed `RawValue`.
    pub fn from_json(json: Box<RawJsonValue>) -> Self {
        Self { json, _ev: PhantomData }
    }

    /// Convert an owned `String` of JSON data to `Raw<T>`.
    ///
    /// This function is equivalent to `serde_json::from_str::<Raw<T>>` except that an allocation
    /// and copy is avoided if both of the following are true:
    ///
    /// * the input has no leading or trailing whitespace, and
    /// * the input has capacity equal to its length.
    pub fn from_json_string(json: String) -> serde_json::Result<Self> {
        RawJsonValue::from_string(json).map(Self::from_json)
    }

    /// Access the underlying json value.
    pub fn json(&self) -> &RawJsonValue {
        &self.json
    }

    /// Convert `self` into the underlying json value.
    pub fn into_json(self) -> Box<RawJsonValue> {
        self.json
    }

    /// Try to access a given field inside this `Raw`, assuming it contains an object.
    ///
    /// Returns `Err(_)` when the contained value is not an object, or the field exists but is fails
    /// to deserialize to the expected type.
    ///
    /// Returns `Ok(None)` when the field doesn't exist or is `null`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # type CustomMatrixEvent = ();
    /// # fn foo() -> serde_json::Result<()> {
    /// # let raw_event: ruma_common::serde::Raw<()> = todo!();
    /// if raw_event.get_field::<String>("type")?.as_deref() == Some("org.custom.matrix.event") {
    ///     let event = raw_event.deserialize_as::<CustomMatrixEvent>()?;
    ///     // ...
    /// }
    /// # Ok(())
    /// # }
    /// ```
    pub fn get_field<'a, U>(&'a self, field_name: &str) -> serde_json::Result<Option<U>>
    where
        U: Deserialize<'a>,
    {
        struct FieldVisitor<'b>(&'b str);

        impl<'b, 'de> Visitor<'de> for FieldVisitor<'b> {
            type Value = bool;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                write!(formatter, "`{}`", self.0)
            }

            fn visit_str<E>(self, value: &str) -> Result<bool, E>
            where
                E: de::Error,
            {
                Ok(value == self.0)
            }
        }

        struct Field<'b>(&'b str);

        impl<'b, 'de> DeserializeSeed<'de> for Field<'b> {
            type Value = bool;

            fn deserialize<D>(self, deserializer: D) -> Result<bool, D::Error>
            where
                D: Deserializer<'de>,
            {
                deserializer.deserialize_identifier(FieldVisitor(self.0))
            }
        }

        struct SingleFieldVisitor<'b, T> {
            field_name: &'b str,
            _phantom: PhantomData<T>,
        }

        impl<'b, T> SingleFieldVisitor<'b, T> {
            fn new(field_name: &'b str) -> Self {
                Self { field_name, _phantom: PhantomData }
            }
        }

        impl<'b, 'de, T> Visitor<'de> for SingleFieldVisitor<'b, T>
        where
            T: Deserialize<'de>,
        {
            type Value = Option<T>;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> std::fmt::Result {
                formatter.write_str("a string")
            }

            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: MapAccess<'de>,
            {
                let mut res = None;
                while let Some(is_right_field) = map.next_key_seed(Field(self.field_name))? {
                    if is_right_field {
                        res = Some(map.next_value()?);
                    } else {
                        map.next_value::<IgnoredAny>()?;
                    }
                }

                Ok(res)
            }
        }

        let mut deserializer = serde_json::Deserializer::from_str(self.json().get());
        deserializer.deserialize_map(SingleFieldVisitor::new(field_name))
    }

    /// Try to deserialize the JSON as the expected type.
    pub fn deserialize<'a>(&'a self) -> serde_json::Result<T>
    where
        T: Deserialize<'a>,
    {
        serde_json::from_str(self.json.get())
    }

    /// Try to deserialize the JSON as a custom type.
    pub fn deserialize_as<'a, U>(&'a self) -> serde_json::Result<U>
    where
        U: Deserialize<'a>,
    {
        serde_json::from_str(self.json.get())
    }

    /// Turns `Raw<T>` into `Raw<U>` without changing the underlying JSON.
    ///
    /// This is useful for turning raw specific event types into raw event enum types.
    pub fn cast<U>(self) -> Raw<U> {
        Raw::from_json(self.into_json())
    }

    /// Turns `&Raw<T>` into `&Raw<U>` without changing the underlying JSON.
    ///
    /// This is useful for turning raw specific event types into raw event enum types.
    pub fn cast_ref<U>(&self) -> &Raw<U> {
        unsafe { mem::transmute(self) }
    }
}

impl<T> Clone for Raw<T> {
    fn clone(&self) -> Self {
        Self::from_json(self.json.clone())
    }
}

impl<T> Debug for Raw<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use std::any::type_name;
        f.debug_struct(&format!("Raw::<{}>", type_name::<T>())).field("json", &self.json).finish()
    }
}

impl<'de, T> Deserialize<'de> for Raw<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        Box::<RawJsonValue>::deserialize(deserializer).map(Self::from_json)
    }
}

impl<T> Serialize for Raw<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        self.json.serialize(serializer)
    }
}

#[cfg(test)]
mod tests {
    use serde::Deserialize;
    use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};

    use super::Raw;

    #[test]
    fn get_field() -> serde_json::Result<()> {
        #[derive(Debug, PartialEq, Deserialize)]
        struct A<'a> {
            #[serde(borrow)]
            b: Vec<&'a str>,
        }

        const OBJ: &str = r#"{ "a": { "b": [  "c"] }, "z": 5 }"#;
        let raw: Raw<()> = from_json_str(OBJ)?;

        assert_eq!(raw.get_field::<u8>("z")?, Some(5));
        assert_eq!(raw.get_field::<&RawJsonValue>("a")?.unwrap().get(), r#"{ "b": [  "c"] }"#);
        assert_eq!(raw.get_field::<A<'_>>("a")?, Some(A { b: vec!["c"] }));

        assert_eq!(raw.get_field::<u8>("b")?, None);
        raw.get_field::<u8>("a").unwrap_err();

        Ok(())
    }
}
<|endoftext|>