<commit_before>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{self, Write, stderr};

use log::LogLevel::Info;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

mod constants;

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(constants::VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("HEADER")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .arg(Arg::with_name("BODY")
            .short("d")
            .long("data")
            .takes_value(true)
            .help("Post Data (Using utf-8 encoding)"))
        .arg(Arg::with_name("UA")
            .short("A")
            .long("user-agent")
            .default_value(constants::USER_AGENT)
            .help("Post Data (Using utf-8 encoding)"))
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .unwrap();
        http::http_query(&request, &mut CabotBinWrite::new(&mut f, verbose), verbose)?;
    } else {
        http::http_query(&request,
                         &mut CabotBinWrite::new(&mut io::stdout(), verbose),
                         verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
        // Unexpexcted Error, not used
        Err(CabotError::HttpResponseParseError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
        Err(CabotError::EncodingError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
    }
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut Write,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut Write, verbose: bool) -> Self {
        CabotBinWrite {
            out: out,
            verbose: verbose,
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {

        let response = String::from_utf8_lossy(buf);
        let response: Vec<&str> = response.splitn(2, "\r\n\r\n").collect();

        // If there is headers and we logged them
        if response.len() == 2 && (log_enabled!(Info) || self.verbose) {
            let headers = response.get(0).unwrap();
            let split = headers.split("\n");
            if log_enabled!(Info) {
                for part in split {
                    info!("< {}", part);
                }
            } else if self.verbose {
                for part in split {
                    writeln!(&mut stderr(), "< {}", part).unwrap();
                }
            }
        }

        let body = if response.len() == 2 {
            response.get(1).unwrap()
        } else {
            response.get(0).unwrap()
        };

        if log_enabled!(Info) {
            info!("< [[{} bytes]]", body.len());
        } else if self.verbose {
            writeln!(&mut stderr(), "< [[{} bytes]]", body.len()).unwrap();
        }

        self.out.write_all(body.as_bytes())?;
        self.flush()?;
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }
}
<commit_msg>Fix binary download<commit_after>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{self, Write, stderr};

use log::LogLevel::Info;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

mod constants;

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(constants::VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("HEADER")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .arg(Arg::with_name("BODY")
            .short("d")
            .long("data")
            .takes_value(true)
            .help("Post Data (Using utf-8 encoding)"))
        .arg(Arg::with_name("UA")
            .short("A")
            .long("user-agent")
            .default_value(constants::USER_AGENT)
            .help("Post Data (Using utf-8 encoding)"))
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");
    let ua = matches.value_of("UA").unwrap();

    let headers: Vec<&str> = match matches.values_of("HEADER") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .set_user_agent(ua)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path)
            .unwrap();
        http::http_query(&request, &mut CabotBinWrite::new(&mut f, verbose), verbose)?;
    } else {
        http::http_query(&request,
                         &mut CabotBinWrite::new(&mut io::stdout(), verbose),
                         verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
        // Unexpexcted Error, not used
        Err(CabotError::HttpResponseParseError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
        Err(CabotError::EncodingError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
    }
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut Write,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut Write, verbose: bool) -> Self {
        CabotBinWrite {
            out: out,
            verbose: verbose,
        }
    }
}

impl<'a> Write for CabotBinWrite<'a> {
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {

        let response = String::from_utf8_lossy(buf);
        let response: Vec<&str> = response.splitn(2, "\r\n\r\n").collect();

        // If there is headers and we logged them
        if response.len() == 2 && (log_enabled!(Info) || self.verbose) {
            let headers = response.get(0).unwrap();
            let split = headers.split("\n");
            if log_enabled!(Info) {
                for part in split {
                    info!("< {}", part);
                }
            } else if self.verbose {
                for part in split {
                    writeln!(&mut stderr(), "< {}", part).unwrap();
                }
            }
        }

        let body = if response.len() == 2 {
            let start = response.get(0).unwrap().len() + 4;
            &buf[start..]
        } else {
            &buf[..]
        };

        if log_enabled!(Info) {
            info!("< [[{} bytes]]", body.len());
        } else if self.verbose {
            writeln!(&mut stderr(), "< [[{} bytes]]", body.len()).unwrap();
        }

        self.out.write_all(body)?;
        self.flush()?;
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        self.out.flush()
    }

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }
}
<|endoftext|>


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

// FIXME: Try the efficient algorithm (takes only O(n) time with additional O(n) space)
// https://de.wikipedia.org/wiki/Suffix-Array-Induced-Sorting
pub fn bwt<F: FnMut(u8)>(mut input: Vec<u8>, mut f: F) -> Vec<u8> {
    input.push(0);

    // get the sorted suffix array
    let mut rotations = (0..input.len()).map(|i| &input[i..]).collect::<Vec<_>>();
    rotations.sort();
    let mut rots = vec![0; input.len()];

    // BWT[i] = S[SA[i] - 1]
    for i in 0..input.len() {
        if rotations[i].len() == input.len() {
            rots[i] = 0;
        } else {
            rots[i] = input[input.len() - rotations[i].len() - 1];
        }

        f(rots[i]);     // call the function with the final value
    }

    rots
}

pub fn occurrence_index(map: HashMap<u8, usize>) -> HashMap<u8, usize> {
    // sort the bytes and locate the index of their first occurrences
    let mut chars = map.keys().collect::<Vec<_>>();
    chars.sort();

    let mut idx = 0;
    let mut occ_map = HashMap::new();
    for i in chars {
        occ_map.insert(*i, idx);
        idx += *map.get(i).unwrap();
    }

    occ_map
}

pub fn ibwt(input: Vec<u8>) -> Vec<u8> {
    // get the byte distribution
    let mut map = HashMap::new();
    for i in &input {
        let mut count = map.entry(*i).or_insert(0);
        *count += 1;
    }

    let mut occ_map = occurrence_index(map);

    // generate the LF vector
    let mut lf = vec![0; input.len()];
    for (i, c) in input.iter().enumerate() {
        let mut val = occ_map.get_mut(&c).unwrap();
        lf[i] = *val;
        *val += 1;
    }

    let mut idx = 0;
    // construct the sequence by traversing through the LF vector
    let mut output = vec![0; input.len()];
    for i in (0..(input.len() - 1)).rev() {
        output[i] = input[idx];
        idx = lf[idx];
    }

    output.pop();
    output
}

pub struct FMIndex {
    data: Vec<u8>,
    count_cache: Vec<usize>,    // remember the occurrence of each char (caching)
    occ_map: HashMap<u8, usize>,
}

impl FMIndex {
    pub fn new(data: Vec<u8>) -> FMIndex {
        let mut idx = 0;
        let mut map = HashMap::new();
        let mut count = vec![0; data.len() + 1];
        let bwt_data = bwt(data, |i| {
            let mut c = map.entry(i).or_insert(0);
            *c += 1;
            count[idx] = *c;
            idx += 1;
        });

        FMIndex {
            occ_map: occurrence_index(map),
            count_cache: count,
            data: bwt_data,
        }
    }

    fn nearest(&self, idx: usize, ch: u8) -> usize {
        match self.occ_map.get(&ch) {
            Some(occ) => {
                occ + (0..idx).rev()
                              .find(|&i| self.data[i] == ch)
                              .map(|i| self.count_cache[i])
                              .unwrap_or(0)
            },
            None => 0,
        }
    }

    // FIXME: We need "checkpointed" index!
    pub fn search(&mut self, query: &str) -> Option<usize> {
        let (mut top, mut bottom) = (0, self.data.len());
        for ch in query.as_bytes().iter().rev() {
            top = self.nearest(top, *ch);
            bottom = self.nearest(bottom, *ch);
        }

        for idx in top..bottom {
            let mut pos = 0;
            let mut i = idx;
            while self.data[i] != 0 {
                pos += 1;
                i = self.nearest(i, self.data[i]);
            }

            return Some(pos)    // break on first find
        }

        None
    }
}
<commit_msg>More caching (use LF-vector for search)<commit_after>use std::collections::HashMap;

// FIXME: Try the efficient algorithm (takes only O(n) time with additional O(n) space)
// https://de.wikipedia.org/wiki/Suffix-Array-Induced-Sorting
pub fn bwt<F: FnMut(u8)>(mut input: Vec<u8>, mut f: F) -> Vec<u8> {
    input.push(0);

    // get the sorted suffix array
    let mut rotations = (0..input.len()).map(|i| &input[i..]).collect::<Vec<_>>();
    rotations.sort();
    let mut rots = vec![0; input.len()];

    // BWT[i] = S[SA[i] - 1]
    for i in 0..input.len() {
        if rotations[i].len() == input.len() {
            rots[i] = 0;
        } else {
            rots[i] = input[input.len() - rotations[i].len() - 1];
        }

        f(rots[i]);     // call the function with the final value
    }

    rots
}

fn occurrence_index(map: HashMap<u8, usize>) -> HashMap<u8, usize> {
    // sort the bytes and locate the index of their first occurrences
    let mut chars = map.keys().collect::<Vec<_>>();
    chars.sort();

    let mut idx = 0;
    let mut occ_map = HashMap::new();
    for i in chars {
        occ_map.insert(*i, idx);
        idx += *map.get(i).unwrap();
    }

    occ_map
}

pub fn ibwt(input: Vec<u8>) -> Vec<u8> {
    // get the byte distribution
    let mut map = HashMap::new();
    for i in &input {
        let mut count = map.entry(*i).or_insert(0);
        *count += 1;
    }

    let mut occ_map = occurrence_index(map);

    // generate the LF vector
    let mut lf = vec![0; input.len()];
    for (i, c) in input.iter().enumerate() {
        let mut val = occ_map.get_mut(&c).unwrap();
        lf[i] = *val;
        *val += 1;
    }

    let mut idx = 0;
    // construct the sequence by traversing through the LF vector
    let mut output = vec![0; input.len()];
    for i in (0..(input.len() - 1)).rev() {
        output[i] = input[idx];
        idx = lf[idx];
    }

    output.pop();
    output
}

#[derive(Clone, Debug)]
pub struct FMIndex {
    /// BW-transformed data
    data: Vec<u8>,
    // forward frequency of each character in the BWT data
    count_cache: Vec<u32>,
    // character frequencies
    occ_map: HashMap<u8, usize>,
    // LF-mapping for backward search
    lf_vec: Vec<u32>,
}

impl FMIndex {
    pub fn new(data: Vec<u8>) -> FMIndex {
        let mut idx = 0;
        let mut map = HashMap::new();
        let mut count = vec![0; data.len() + 1];
        let bwt_data = bwt(data, |i| {
            let mut c = map.entry(i).or_insert(0);
            *c += 1;
            count[idx] = *c as u32;
            idx += 1;
        });

        let occ_map = occurrence_index(map);
        let mut lf_occ_map = occ_map.clone();
        let mut lf_vec = vec![0; bwt_data.len()];
        for (i, c) in bwt_data.iter().enumerate() {
            let mut val = lf_occ_map.get_mut(&c).unwrap();
            lf_vec[i] = *val as u32;
            *val += 1;
        }

        FMIndex {
            occ_map: occ_map,
            count_cache: count,
            data: bwt_data,
            lf_vec: lf_vec,
        }
    }

    fn nearest(&self, idx: usize, ch: u8) -> usize {
        match self.occ_map.get(&ch) {
            Some(occ) => {
                occ + (0..idx).rev()
                              .find(|&i| self.data[i] == ch)
                              .map(|i| self.count_cache[i] as usize)
                              .unwrap_or(0)
            },
            None => 0,
        }
    }

    pub fn search(&self, query: &str) -> Option<usize> {
        let mut top = 0;
        let mut bottom = self.data.len();
        for ch in query.as_bytes().iter().rev() {
            top = self.nearest(top, *ch);
            bottom = self.nearest(bottom, *ch);
        }

        for idx in top..bottom {
            let mut i = self.nearest(idx, self.data[idx]);
            let mut pos = 1;
            while self.data[i] != 0 {
                pos += 1;
                i = self.lf_vec[i] as usize;
            }

            return Some(pos % self.data.len())      // break on first find
        }

        None
    }
}
<|endoftext|>


<commit_before>use std::string::String;
use std::io;
use std::io::prelude::*;

use regex::Regex;

use platform::EOL_LEN;
use commands::*;
use REHolder;

static CLI_PROMPT: &'static str = "#> ";

fn cli_request(command: &mut String) {
    print!("\n{welcome}", welcome = CLI_PROMPT);
    io::stdout().flush().unwrap();
    io::stdin().read_line(command).expect("Failed to read command!");
    let len = command.len();
    command.truncate(len - EOL_LEN as usize);
}

fn parse_and_execute(command: &String, mut current_re: &mut REHolder) -> String {

    let space_pos = match command.find(' ') {
        None => command.len(),
        Some(pos) => pos
    };

    let (com, arg) = command.split_at(space_pos);
    let arg = arg.trim();

    println!("Command was: {}", com);
    println!("Args was: {}", arg);

    match com.as_ref() {
        "help" => show_help(),
        "re" => set_regex(&arg, &mut current_re),
        _ => default_command()
    }
}

pub fn cli_parse_command(mut current_re: &mut REHolder) -> bool {
    let mut command = String::new();
    cli_request(&mut command);

    if command == "exit" {
        return false;
    }

    let result = parse_and_execute(&command, &mut current_re);
    println!("{}", result);

    true
}

<commit_msg>ignore new-line command<commit_after>use std::string::String;
use std::io;
use std::io::prelude::*;

use regex::Regex;

use platform::EOL_LEN;
use commands::*;
use REHolder;

static CLI_PROMPT: &'static str = "#> ";

fn cli_request(command: &mut String) {
    print!("\n{welcome}", welcome = CLI_PROMPT);
    io::stdout().flush().unwrap();
    io::stdin().read_line(command).expect("Failed to read command!");
    let len = command.len();
    command.truncate(len - EOL_LEN as usize);
}

fn parse_and_execute(command: &String, mut current_re: &mut REHolder) -> String {

    let space_pos = match command.find(' ') {
        None => command.len(),
        Some(pos) => pos
    };

    let (com, arg) = command.split_at(space_pos);
    let arg = arg.trim();

    match com.as_ref() {
        "help" => show_help(),
        "re" => set_regex(&arg, &mut current_re),
        _ => default_command()
    }
}

pub fn cli_parse_command(mut current_re: &mut REHolder) -> bool {
    let mut command = String::new();
    cli_request(&mut command);

    if command == "exit" {
        return false;
    }

    if command.len() > 0 {
        let result = parse_and_execute(&command, &mut current_re);
        println!("{}", result);
    }

    true
}

<|endoftext|>


<commit_before>/// Calculates the 32bit crc from a given set of data. It does not appear to
/// be the typical crc calculation and may be specific to Rocket League and/or
/// Unreal Engine. Implementation is close, but not the same as the crc create
pub fn calc_crc(data: &[u8]) -> u32 {
    let mut crc: u32 = !(0xefcb_f201);

    for &i in data.iter() {
        crc = (crc << 8) ^ (TABLE[((u32::from(i)) ^ (crc >> 24)) as usize]);
    }
    !crc
}

/// Precomputed crc table. It is extremely close to IEEE housed in the
/// crc crate, but they are not interchangeable. Still need to determine
/// the differences. Copied from the Octane project.
static TABLE: [u32; 256] =
    [0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2,
     0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3,
     0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
     0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
     0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
     0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
     0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90,
     0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
     0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a,
     0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
     0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13,
     0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
     0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
     0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20,
     0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
     0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
     0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055,
     0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
     0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632,
     0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
     0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0,
     0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91,
     0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
     0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
     0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
     0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615,
     0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a,
     0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
     0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f,
     0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
     0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651,
     0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
     0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
     0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa,
     0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
     0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
     0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4];
<commit_msg>Add explicit crc test<commit_after>/// Calculates the 32bit crc from a given set of data. It does not appear to
/// be the typical crc calculation and may be specific to Rocket League and/or
/// Unreal Engine. Implementation is close, but not the same as the crc create
pub fn calc_crc(data: &[u8]) -> u32 {
    let mut crc: u32 = !(0xefcb_f201);

    for &i in data.iter() {
        crc = (crc << 8) ^ (TABLE[((u32::from(i)) ^ (crc >> 24)) as usize]);
    }
    !crc
}

/// Precomputed crc table. It is extremely close to IEEE housed in the
/// crc crate, but they are not interchangeable. Still need to determine
/// the differences. Copied from the Octane project.
static TABLE: [u32; 256] =
    [0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2,
     0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3,
     0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
     0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
     0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e,
     0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
     0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90,
     0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
     0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a,
     0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c,
     0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13,
     0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
     0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
     0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20,
     0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f,
     0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
     0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055,
     0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
     0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632,
     0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
     0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0,
     0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91,
     0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
     0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
     0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604,
     0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615,
     0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a,
     0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
     0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f,
     0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
     0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651,
     0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
     0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
     0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa,
     0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5,
     0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
     0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4];

#[cfg(test)]
mod tests {
    use crc::calc_crc;

    #[test]
    fn crc_rumble_test() {
        let data = include_bytes!("../assets/rumble.replay");
        assert_eq!(calc_crc(&data[..]), 2034487435);
    }
}
<|endoftext|>


<commit_before>use error::{ToResult};
use std::env;
use std::path::{PathBuf};

pub fn resolve(pathname: &str) -> ToResult<PathBuf> {
    let mut absolute = try!(env::current_dir());
            absolute.push(pathname);

    let canonical = try!(absolute.canonicalize());

    return Ok(canonical);
}

pub fn basename(path: &PathBuf) -> ToResult<String> {
    if let Some(stem) = path.file_stem() {
        let os_string = stem.to_os_string();

        return match os_string.into_string() {
            Ok(string) => Ok(string),
            Err(_) => Ok(String::from("")),
        };
    }

    return Ok(String::from(""));
}

pub fn config() -> ToResult<PathBuf> {
    let mut directory = match env::home_dir() {
        Some(value) => value,
        None => panic!("TODO: Custom error - unable to locate home directory."),
    };

    directory.push(".to");

    return Ok(directory);
}

#[cfg(test)]
mod tests {
    extern crate env_logger;

    use std::env;
    use std::path::{PathBuf};
    use super::*;

    #[test]
    fn resolve_relative() {
        let actual = resolve("src").expect("should not fail");
        let mut expected = env::current_dir().expect("should not fail");
                expected.push("src");
        assert_eq!(actual, expected);

        let actual = resolve("src").expect("should not fail");
        assert_eq!(actual, expected);
    }

    #[test]
    fn resolve_dot() {
        let actual = resolve(".").expect("should not fail");
        let expected = env::current_dir().expect("should not fail");

        assert_eq!(actual, expected);
    }

    #[test]
    fn resolve_dot_dot() {
        let actual = resolve("../to-directory/src").expect("should not fail");
        let mut expected = env::current_dir().expect("should not fail");
                expected.pop();
                expected.push("to-directory");
                expected.push("src");

        assert_eq!(actual, expected);
    }

    #[test]
    fn basename_absolute() {
        let pathname = PathBuf::from("/foo/bar");
        let basename = basename(&pathname).expect("should not fail");

        assert_eq!(basename, String::from("bar"));
    }
}
<commit_msg>Adds db path resolution to dir.<commit_after>use error::{ToResult};
use std::env;
use std::path::{PathBuf};

pub fn resolve(pathname: &str) -> ToResult<PathBuf> {
    let mut absolute = try!(env::current_dir());
            absolute.push(pathname);

    let canonical = try!(absolute.canonicalize());

    return Ok(canonical);
}

pub fn basename(path: &PathBuf) -> ToResult<String> {
    if let Some(stem) = path.file_stem() {
        let os_string = stem.to_os_string();

        return match os_string.into_string() {
            Ok(string) => Ok(string),
            Err(_) => Ok(String::from("")),
        };
    }

    return Ok(String::from(""));
}

pub fn config() -> ToResult<PathBuf> {
    let mut directory = match env::home_dir() {
        Some(value) => value,
        None => panic!("TODO: Custom error - unable to locate home directory."),
    };

    directory.push(".to");

    return Ok(directory);
}

pub fn db() -> ToResult<PathBuf> {
    let mut pathname = try!(config());
            pathname.push("db");
    return Ok(pathname);
}

#[cfg(test)]
mod tests {
    extern crate env_logger;

    use std::env;
    use std::path::{PathBuf};
    use super::*;

    #[test]
    fn resolve_relative() {
        let actual = resolve("src").expect("should not fail");
        let mut expected = env::current_dir().expect("should not fail");
                expected.push("src");
        assert_eq!(actual, expected);

        let actual = resolve("src").expect("should not fail");
        assert_eq!(actual, expected);
    }

    #[test]
    fn resolve_dot() {
        let actual = resolve(".").expect("should not fail");
        let expected = env::current_dir().expect("should not fail");

        assert_eq!(actual, expected);
    }

    #[test]
    fn resolve_dot_dot() {
        let actual = resolve("../to-directory/src").expect("should not fail");
        let mut expected = env::current_dir().expect("should not fail");
                expected.pop();
                expected.push("to-directory");
                expected.push("src");

        assert_eq!(actual, expected);
    }

    #[test]
    fn basename_absolute() {
        let pathname = PathBuf::from("/foo/bar");
        let basename = basename(&pathname).expect("should not fail");

        assert_eq!(basename, String::from("bar"));
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2021 Rene van der Meer
//
// 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.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use core::convert::Infallible;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use spin_sleep::sleep;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay {}

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u8) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u16> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u16) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u32> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u64> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u64) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(ms));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayUs<u8> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u8) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u16> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u16) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u32> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u64> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u64) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        self.try_delay_us(us).unwrap()
    }
}

/// Newtype wrapper for `f64`. Converts into `Duration`.
pub struct Hertz(pub f64);

const MICROS_PER_SEC: f64 = 1_000_000.0;

impl From<Hertz> for Duration {
    fn from(item: Hertz) -> Self {
        if item.0 > 0.0 && item.0.is_finite() {
            Duration::from_micros(((1.0 / item.0) * MICROS_PER_SEC) as u64)
        } else {
            Duration::default()
        }
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    start: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            start: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

impl CountDown for Timer {
    type Time = Duration;
    type Error = Infallible;

    /// Starts the timer with a `timeout`.
    fn try_start<T>(&mut self, timeout: T) -> Result<(), Self::Error>
    where
        T: Into<Self::Time>,
    {
        self.start = Instant::now();
        self.duration = timeout.into();
        Ok(())
    }

    /// Returns `Ok` if the timer has wrapped.
    fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
        if self.start.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

impl embedded_hal_0::timer::CountDown for Timer {
    type Time = Duration;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Self::Time>,
    {
        self.try_start(timeout).unwrap()
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        Ok(self.try_wait().unwrap())
    }
}
<commit_msg>Fix `Delay` struct.<commit_after>// Copyright (c) 2017-2021 Rene van der Meer
//
// 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.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use core::convert::Infallible;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use spin_sleep::sleep;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay;

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u8) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u16> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u16) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u32> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(u64::from(ms)));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayMs<u64> for Delay {
    type Error = Infallible;

    fn try_delay_ms(&mut self, ms: u64) -> Result<(), Self::Error> {
        sleep(Duration::from_millis(ms));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        self.try_delay_ms(ms).unwrap()
    }
}

impl DelayUs<u8> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u8) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u16> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u16) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u32> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us.into()));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        self.try_delay_us(us).unwrap()
    }
}

impl DelayUs<u64> for Delay {
    type Error = Infallible;

    fn try_delay_us(&mut self, us: u64) -> Result<(), Self::Error> {
        sleep(Duration::from_micros(us));
        Ok(())
    }
}

impl embedded_hal_0::blocking::delay::DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        self.try_delay_us(us).unwrap()
    }
}

/// Newtype wrapper for `f64`. Converts into `Duration`.
pub struct Hertz(pub f64);

const MICROS_PER_SEC: f64 = 1_000_000.0;

impl From<Hertz> for Duration {
    fn from(item: Hertz) -> Self {
        if item.0 > 0.0 && item.0.is_finite() {
            Duration::from_micros(((1.0 / item.0) * MICROS_PER_SEC) as u64)
        } else {
            Duration::default()
        }
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    start: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            start: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

impl CountDown for Timer {
    type Time = Duration;
    type Error = Infallible;

    /// Starts the timer with a `timeout`.
    fn try_start<T>(&mut self, timeout: T) -> Result<(), Self::Error>
    where
        T: Into<Self::Time>,
    {
        self.start = Instant::now();
        self.duration = timeout.into();
        Ok(())
    }

    /// Returns `Ok` if the timer has wrapped.
    fn try_wait(&mut self) -> nb::Result<(), Self::Error> {
        if self.start.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

impl embedded_hal_0::timer::CountDown for Timer {
    type Time = Duration;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Self::Time>,
    {
        self.try_start(timeout).unwrap()
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        Ok(self.try_wait().unwrap())
    }
}
<|endoftext|>


<commit_before>/// Enable Interrupts.
pub unsafe fn enable()
{
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable()
{
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// Load IDT table.
pub unsafe fn lidt(idt: u64)
{
    asm!("lidt (%rax)" :: "{rax}" (idt));
}

<commit_msg>IDT representations added.<commit_after>/// Enable Interrupts.
pub unsafe fn enable()
{
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable()
{
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// A struct describing an interrupt gate.
#[derive(Debug, Copy)]
#[repr(packed)]
pub struct IdtEntry {
    /// Lower 16 bits of ISR.
    pub base_lo: u16,
    /// Segment selector.
    pub sel: u16,
    /// This must always be zero.
    pub res0: u8,
    /// Flags.
    pub flags: u8,
    /// The upper 48 bits of ISR (the last 16 bits must be zero).
    pub base_hi: u64,
    /// Must be zero.
    pub res1: u16
}

/// A struct describing a pointer to an array of interrupt handlers.
/// This is in a format suitable for giving to 'lidt'.
#[derive(Debug)]
#[repr(packed)]
pub struct IdtPointer
{
   /// Size of the IDT.
   pub limit: u16,
   /// Pointer to the memory region containing the IDT.
   pub base: u64
}

/// Load IDT table.
pub unsafe fn lidt(idt: u64)
{
    asm!("lidt (%rax)" :: "{rax}" (idt));
}

<|endoftext|>


<commit_before>use expect_test::expect;

use crate::TopEntryPoint;

#[test]
fn source_file() {
    check(
        TopEntryPoint::SourceFile,
        "",
        expect![[r#"
        SOURCE_FILE
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "struct S;",
        expect![[r#"
        SOURCE_FILE
          STRUCT
            STRUCT_KW "struct"
            WHITESPACE " "
            NAME
              IDENT "S"
            SEMICOLON ";"
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "@error@",
        expect![[r#"
        SOURCE_FILE
          ERROR
            AT "@"
          MACRO_CALL
            PATH
              PATH_SEGMENT
                NAME_REF
                  IDENT "error"
          ERROR
            AT "@"
        error 0: expected an item
        error 6: expected BANG
        error 6: expected `{`, `[`, `(`
        error 6: expected SEMICOLON
        error 6: expected an item
    "#]],
    );
}

#[test]
fn macro_stmt() {
    check(
        TopEntryPoint::MacroStmts,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_STMTS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected expression
        "##]],
    );
    check(
        TopEntryPoint::MacroStmts,
        "let x = 1 2 struct S;",
        expect![[r#"
            MACRO_STMTS
              LET_STMT
                LET_KW "let"
                WHITESPACE " "
                IDENT_PAT
                  NAME
                    IDENT "x"
                WHITESPACE " "
                EQ "="
                WHITESPACE " "
                LITERAL
                  INT_NUMBER "1"
              WHITESPACE " "
              EXPR_STMT
                LITERAL
                  INT_NUMBER "2"
              WHITESPACE " "
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
        "#]],
    );
}

#[test]
fn macro_items() {
    check(
        TopEntryPoint::MacroItems,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_ITEMS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected an item
        "##]],
    );
    check(
        TopEntryPoint::MacroItems,
        "struct S; foo!{}",
        expect![[r#"
            MACRO_ITEMS
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
              WHITESPACE " "
              MACRO_CALL
                PATH
                  PATH_SEGMENT
                    NAME_REF
                      IDENT "foo"
                BANG "!"
                TOKEN_TREE
                  L_CURLY "{"
                  R_CURLY "}"
        "#]],
    );
}

#[test]
fn macro_pattern() {
    check(
        TopEntryPoint::Pattern,
        "Some(_)",
        expect![[r#"
            TUPLE_STRUCT_PAT
              PATH
                PATH_SEGMENT
                  NAME_REF
                    IDENT "Some"
              L_PAREN "("
              WILDCARD_PAT
                UNDERSCORE "_"
              R_PAREN ")"
        "#]],
    );

    check(
        TopEntryPoint::Pattern,
        "None leftover tokens",
        expect![[r#"
            ERROR
              IDENT_PAT
                NAME
                  IDENT "None"
              WHITESPACE " "
              IDENT "leftover"
              WHITESPACE " "
              IDENT "tokens"
        "#]],
    );

    check(
        TopEntryPoint::Pattern,
        "@err",
        expect![[r#"
            ERROR
              ERROR
                AT "@"
              IDENT "err"
            error 0: expected pattern
        "#]],
    );
}

#[test]
fn type_() {
    check(
        TopEntryPoint::Type,
        "Option<!>",
        expect![[r#"
            PATH_TYPE
              PATH
                PATH_SEGMENT
                  NAME_REF
                    IDENT "Option"
                  GENERIC_ARG_LIST
                    L_ANGLE "<"
                    TYPE_ARG
                      NEVER_TYPE
                        BANG "!"
                    R_ANGLE ">"
        "#]],
    );
    check(
        TopEntryPoint::Type,
        "() () ()",
        expect![[r#"
            ERROR
              TUPLE_TYPE
                L_PAREN "("
                R_PAREN ")"
              WHITESPACE " "
              L_PAREN "("
              R_PAREN ")"
              WHITESPACE " "
              L_PAREN "("
              R_PAREN ")"
        "#]],
    );
    check(
        TopEntryPoint::Type,
        "$$$",
        expect![[r#"
            ERROR
              ERROR
                DOLLAR "$"
              DOLLAR "$"
              DOLLAR "$"
            error 0: expected type
        "#]],
    );
}

#[test]
fn expr() {
    check(
        TopEntryPoint::Expr,
        "2 + 2 == 5",
        expect![[r#"
        BIN_EXPR
          BIN_EXPR
            LITERAL
              INT_NUMBER "2"
            WHITESPACE " "
            PLUS "+"
            WHITESPACE " "
            LITERAL
              INT_NUMBER "2"
          WHITESPACE " "
          EQ2 "=="
          WHITESPACE " "
          LITERAL
            INT_NUMBER "5"
    "#]],
    );
    check(
        TopEntryPoint::Expr,
        "let _ = 0;",
        expect![[r#"
        ERROR
          LET_KW "let"
          WHITESPACE " "
          UNDERSCORE "_"
          WHITESPACE " "
          EQ "="
          WHITESPACE " "
          INT_NUMBER "0"
          SEMICOLON ";"
        error 0: expected expression
    "#]],
    );
}

#[track_caller]
fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
    let (parsed, _errors) = super::parse(entry, input);
    expect.assert_eq(&parsed)
}
<commit_msg>add empty input tests<commit_after>use expect_test::expect;

use crate::TopEntryPoint;

#[test]
fn source_file() {
    check(
        TopEntryPoint::SourceFile,
        "",
        expect![[r#"
        SOURCE_FILE
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "struct S;",
        expect![[r#"
        SOURCE_FILE
          STRUCT
            STRUCT_KW "struct"
            WHITESPACE " "
            NAME
              IDENT "S"
            SEMICOLON ";"
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "@error@",
        expect![[r#"
        SOURCE_FILE
          ERROR
            AT "@"
          MACRO_CALL
            PATH
              PATH_SEGMENT
                NAME_REF
                  IDENT "error"
          ERROR
            AT "@"
        error 0: expected an item
        error 6: expected BANG
        error 6: expected `{`, `[`, `(`
        error 6: expected SEMICOLON
        error 6: expected an item
    "#]],
    );
}

#[test]
fn macro_stmt() {
    check(
        TopEntryPoint::MacroStmts,
        "",
        expect![[r#"
            MACRO_STMTS
        "#]],
    );
    check(
        TopEntryPoint::MacroStmts,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_STMTS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected expression
        "##]],
    );
    check(
        TopEntryPoint::MacroStmts,
        "let x = 1 2 struct S;",
        expect![[r#"
            MACRO_STMTS
              LET_STMT
                LET_KW "let"
                WHITESPACE " "
                IDENT_PAT
                  NAME
                    IDENT "x"
                WHITESPACE " "
                EQ "="
                WHITESPACE " "
                LITERAL
                  INT_NUMBER "1"
              WHITESPACE " "
              EXPR_STMT
                LITERAL
                  INT_NUMBER "2"
              WHITESPACE " "
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
        "#]],
    );
}

#[test]
fn macro_items() {
    check(
        TopEntryPoint::MacroItems,
        "",
        expect![[r#"
            MACRO_ITEMS
        "#]],
    );
    check(
        TopEntryPoint::MacroItems,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_ITEMS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected an item
        "##]],
    );
    check(
        TopEntryPoint::MacroItems,
        "struct S; foo!{}",
        expect![[r#"
            MACRO_ITEMS
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
              WHITESPACE " "
              MACRO_CALL
                PATH
                  PATH_SEGMENT
                    NAME_REF
                      IDENT "foo"
                BANG "!"
                TOKEN_TREE
                  L_CURLY "{"
                  R_CURLY "}"
        "#]],
    );
}

#[test]
fn macro_pattern() {
    check(
        TopEntryPoint::Pattern,
        "",
        expect![[r#"
            ERROR
            error 0: expected pattern
        "#]],
    );
    check(
        TopEntryPoint::Pattern,
        "Some(_)",
        expect![[r#"
            TUPLE_STRUCT_PAT
              PATH
                PATH_SEGMENT
                  NAME_REF
                    IDENT "Some"
              L_PAREN "("
              WILDCARD_PAT
                UNDERSCORE "_"
              R_PAREN ")"
        "#]],
    );

    check(
        TopEntryPoint::Pattern,
        "None leftover tokens",
        expect![[r#"
            ERROR
              IDENT_PAT
                NAME
                  IDENT "None"
              WHITESPACE " "
              IDENT "leftover"
              WHITESPACE " "
              IDENT "tokens"
        "#]],
    );

    check(
        TopEntryPoint::Pattern,
        "@err",
        expect![[r#"
            ERROR
              ERROR
                AT "@"
              IDENT "err"
            error 0: expected pattern
        "#]],
    );
}

#[test]
fn type_() {
    check(
        TopEntryPoint::Type,
        "",
        expect![[r#"
            ERROR
            error 0: expected type
        "#]],
    );

    check(
        TopEntryPoint::Type,
        "Option<!>",
        expect![[r#"
            PATH_TYPE
              PATH
                PATH_SEGMENT
                  NAME_REF
                    IDENT "Option"
                  GENERIC_ARG_LIST
                    L_ANGLE "<"
                    TYPE_ARG
                      NEVER_TYPE
                        BANG "!"
                    R_ANGLE ">"
        "#]],
    );
    check(
        TopEntryPoint::Type,
        "() () ()",
        expect![[r#"
            ERROR
              TUPLE_TYPE
                L_PAREN "("
                R_PAREN ")"
              WHITESPACE " "
              L_PAREN "("
              R_PAREN ")"
              WHITESPACE " "
              L_PAREN "("
              R_PAREN ")"
        "#]],
    );
    check(
        TopEntryPoint::Type,
        "$$$",
        expect![[r#"
            ERROR
              ERROR
                DOLLAR "$"
              DOLLAR "$"
              DOLLAR "$"
            error 0: expected type
        "#]],
    );
}

#[test]
fn expr() {
    check(
        TopEntryPoint::Expr,
        "",
        expect![[r#"
            ERROR
            error 0: expected expression
        "#]],
    );
    check(
        TopEntryPoint::Expr,
        "2 + 2 == 5",
        expect![[r#"
        BIN_EXPR
          BIN_EXPR
            LITERAL
              INT_NUMBER "2"
            WHITESPACE " "
            PLUS "+"
            WHITESPACE " "
            LITERAL
              INT_NUMBER "2"
          WHITESPACE " "
          EQ2 "=="
          WHITESPACE " "
          LITERAL
            INT_NUMBER "5"
    "#]],
    );
    check(
        TopEntryPoint::Expr,
        "let _ = 0;",
        expect![[r#"
        ERROR
          LET_KW "let"
          WHITESPACE " "
          UNDERSCORE "_"
          WHITESPACE " "
          EQ "="
          WHITESPACE " "
          INT_NUMBER "0"
          SEMICOLON ";"
        error 0: expected expression
    "#]],
    );
}

#[track_caller]
fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
    let (parsed, _errors) = super::parse(entry, input);
    expect.assert_eq(&parsed)
}
<|endoftext|>


<commit_before>use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast, SyntaxNode,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };
    let strukt_def = ctx.sema.to_def(&strukt)?;

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, strukt_def, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: hir::Struct,
    names: &[ast::Name],
) {
    let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
        match_ast! {
            match node {
                ast::TupleStructPat(tuple_struct_pat) => {
                    edit.replace(
                        tuple_struct_pat.syntax().text_range(),
                        ast::make::record_pat_with_fields(
                            tuple_struct_pat.path()?,
                            ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                |(pat, name)| {
                                    ast::make::record_pat_field(
                                        ast::make::name_ref(&name.to_string()),
                                        pat,
                                    )
                                },
                            )),
                        )
                        .to_string(),
                    );
                },
                // for tuple struct creations like Foo(42)
                ast::CallExpr(call_expr) => {
                    let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?;

                    // this also includes method calls like Foo::new(42), we should skip them
                    if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) {
                        match NameRefClass::classify(&ctx.sema, &name_ref) {
                            Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                            Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                            _ => return None,
                        };
                    }

                    let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;

                    edit.replace(
                        call_expr.syntax().text_range(),
                        ast::make::record_expr(
                            path,
                            ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                |(expr, name)| {
                                    ast::make::record_expr_field(
                                        ast::make::name_ref(&name.to_string()),
                                        Some(expr),
                                    )
                                },
                            )),
                        )
                        .to_string(),
                    );
                },
                _ => ()
            }
        }
        Some(())
    };

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                edit_node(edit, node);
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_multi_file_references() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
//- /main.rs
struct Inner;
struct A$0(Inner);

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A(Inner);
}
"#,
            r#"
//- /main.rs
struct Inner;
struct A { field1: Inner }

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A { field1: Inner };
}
"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<commit_msg>Stop iterating reference after made an edit in "Convert to named struct" assist<commit_after>use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast, SyntaxNode,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };
    let strukt_def = ctx.sema.to_def(&strukt)?;

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, strukt_def, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: hir::Struct,
    names: &[ast::Name],
) {
    let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
        match_ast! {
            match node {
                ast::TupleStructPat(tuple_struct_pat) => {
                    edit.replace(
                        tuple_struct_pat.syntax().text_range(),
                        ast::make::record_pat_with_fields(
                            tuple_struct_pat.path()?,
                            ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                |(pat, name)| {
                                    ast::make::record_pat_field(
                                        ast::make::name_ref(&name.to_string()),
                                        pat,
                                    )
                                },
                            )),
                        )
                        .to_string(),
                    );
                },
                // for tuple struct creations like Foo(42)
                ast::CallExpr(call_expr) => {
                    let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?;

                    // this also includes method calls like Foo::new(42), we should skip them
                    if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) {
                        match NameRefClass::classify(&ctx.sema, &name_ref) {
                            Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                            Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                            _ => return None,
                        };
                    }

                    let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;

                    edit.replace(
                        call_expr.syntax().text_range(),
                        ast::make::record_expr(
                            path,
                            ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                |(expr, name)| {
                                    ast::make::record_expr_field(
                                        ast::make::name_ref(&name.to_string()),
                                        Some(expr),
                                    )
                                },
                            )),
                        )
                        .to_string(),
                    );
                },
                _ => return None,
            }
        }
        Some(())
    };

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                if edit_node(edit, node).is_some() {
                    break;
                }
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_wrapped_references() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner$0(u32);
struct Outer(Inner);

impl Outer {
    fn new() -> Self {
        Self(Inner(42))
    }

    fn into_inner(self) -> u32 {
        (self.0).0
    }

    fn into_inner_destructed(self) -> u32 {
        let Outer(Inner(x)) = self;
        x
    }
}"#,
            r#"
struct Inner { field1: u32 }
struct Outer(Inner);

impl Outer {
    fn new() -> Self {
        Self(Inner { field1: 42 })
    }

    fn into_inner(self) -> u32 {
        (self.0).field1
    }

    fn into_inner_destructed(self) -> u32 {
        let Outer(Inner { field1: x }) = self;
        x
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_multi_file_references() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
//- /main.rs
struct Inner;
struct A$0(Inner);

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A(Inner);
}
"#,
            r#"
//- /main.rs
struct Inner;
struct A { field1: Inner }

mod foo;

//- /foo.rs
use crate::{A, Inner};
fn f() {
    let a = A { field1: Inner };
}
"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<|endoftext|>