<commit_before>use pnet_macros::Packet;
use pnet_macros_support::types::{u1, u3, u4, u7, u16le, u32le, u64le};
use pnet_macros_support::packet::PrimitiveValues;

/// Represents a USB PCAP function for the requested operation.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UsbPcapFunction(pub u16);

impl UsbPcapFunction {
    /// Construct a new `UsbPcapFunction` instance.
    pub fn new(val: u16) -> Self {
        Self(val)
    }
}

impl PrimitiveValues for UsbPcapFunction {
    type T = (u16,);
    fn to_primitive_values(&self) -> Self::T {
        (self.0,)
    }
}

/// Represents the USB status for USB requests.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UsbPcapStatus(pub u32);

impl UsbPcapStatus {
    /// Construct a new `UsbPcapStatus` instance.
    pub fn new(val: u32) -> Self {
        Self(val)
    }
}

impl PrimitiveValues for UsbPcapStatus {
    type T = (u32,);
    fn to_primitive_values(&self) -> Self::T {
        (self.0,)
    }
}

/// Represents a USB PCAP packet ([Link Type 249](https://www.tcpdump.org/linktypes.html)).
#[derive(Packet)]
pub struct UsbPcap {
    pub header_length: u16le,
    pub irp_id: u64le,
    #[construct_with(u32le)]
    pub status: UsbPcapStatus,
    #[construct_with(u16le)]
    pub function: UsbPcapFunction,
    pub reserved_info: u7,
    pub pdo_to_fdo: u1,
    pub bus: u16le,
    pub device: u16le,
    pub direction: u1,
    pub reserved_endpoint: u3,
    pub endpoint: u4,
    pub transfer: u8,
    pub data_length: u32le,
    #[length = "header_length - 27"]
    pub header_payload: Vec<u8>,
    #[length = "data_length"]
    #[payload]
    pub payload: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use pnet_macros_support::packet::Packet;

    #[test]
    fn usbpcap_packet_test() {
        let mut packet = [0u8; 35];
        {
            let mut usbpcap = MutableUsbPcapPacket::new(&mut packet[..]).unwrap();
            usbpcap.set_header_length(27);
            assert_eq!(usbpcap.get_header_length(), 27);

            usbpcap.set_irp_id(0x12_34);
            assert_eq!(usbpcap.get_irp_id(), 0x12_34);

            usbpcap.set_status(UsbPcapStatus(30));
            assert_eq!(usbpcap.get_status(), UsbPcapStatus(30));

            usbpcap.set_function(UsbPcapFunction(40));
            assert_eq!(usbpcap.get_function(), UsbPcapFunction(40));

            assert_eq!(usbpcap.get_reserved_info(), 0);

            usbpcap.set_pdo_to_fdo(1);
            assert_eq!(usbpcap.get_pdo_to_fdo(), 1);

            usbpcap.set_bus(60);
            assert_eq!(usbpcap.get_bus(), 60);

            usbpcap.set_device(70);
            assert_eq!(usbpcap.get_device(), 70);

            usbpcap.set_direction(1);
            assert_eq!(usbpcap.get_direction(), 1);

            assert_eq!(usbpcap.get_reserved_endpoint(), 0);

            usbpcap.set_endpoint(14);
            assert_eq!(usbpcap.get_endpoint(), 14);

            usbpcap.set_transfer(80);
            assert_eq!(usbpcap.get_transfer(), 80);

            usbpcap.set_data_length(2);
            assert_eq!(usbpcap.get_data_length(), 2);

            assert_eq!(usbpcap.get_header_payload(), &[]);

            usbpcap.set_payload(&[90, 100]);
            assert_eq!(usbpcap.payload(), &[90, 100]);
        }

        let ref_packet = [
            27, 0, // Header length
            0x34, 0x12, 0, 0, 0, 0, 0, 0, // IRP ID
            30, 0, 0, 0, // Status
            40, 0, // Function
            1, // Info octet
            60, 0, // Bus
            70, 0, // Device
            142, // Endpoint fields
            80, // Transfer field
            2, 0, 0, 0, // Data length field
            // No header payload
            90, 100 // Payload
        ];

        assert_eq!(&ref_packet[..], &packet[0..29]);
    }

    #[test]
    fn usbpcap_packet_test_variable_header() {
        let mut packet = [0u8; 35];
        {
            let mut usbpcap = MutableUsbPcapPacket::new(&mut packet[..]).unwrap();
            usbpcap.set_header_length(28);
            assert_eq!(usbpcap.get_header_length(), 28);

            usbpcap.set_header_payload(&[110]);
            assert_eq!(usbpcap.get_header_payload(), &[110]);

            assert_eq!(usbpcap.payload(), &[]);
        }

        let ref_packet = [
            28, 0, // Header length
            0, 0, 0, 0, 0, 0, 0, 0, // IRP ID
            0, 0, 0, 0, // Status
            0, 0, // Function
            0, // Info
            0, 0, // Bus
            0, 0, // Device
            0, // Endpoint fields
            0, // Transfer field
            0, 0, 0, 0, // Data length field
            110, // Header payload
            // No payload
        ];

        assert_eq!(&ref_packet[..], &packet[0..28]);
    }
}<commit_msg>Adds a missing doc comment for the usbpcap module.<commit_after>//! A USB PCAP packet abstraction.
use pnet_macros::Packet;
use pnet_macros_support::types::{u1, u3, u4, u7, u16le, u32le, u64le};
use pnet_macros_support::packet::PrimitiveValues;

/// Represents a USB PCAP function for the requested operation.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UsbPcapFunction(pub u16);

impl UsbPcapFunction {
    /// Construct a new `UsbPcapFunction` instance.
    pub fn new(val: u16) -> Self {
        Self(val)
    }
}

impl PrimitiveValues for UsbPcapFunction {
    type T = (u16,);
    fn to_primitive_values(&self) -> Self::T {
        (self.0,)
    }
}

/// Represents the USB status for USB requests.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UsbPcapStatus(pub u32);

impl UsbPcapStatus {
    /// Construct a new `UsbPcapStatus` instance.
    pub fn new(val: u32) -> Self {
        Self(val)
    }
}

impl PrimitiveValues for UsbPcapStatus {
    type T = (u32,);
    fn to_primitive_values(&self) -> Self::T {
        (self.0,)
    }
}

/// Represents a USB PCAP packet ([Link Type 249](https://www.tcpdump.org/linktypes.html)).
#[derive(Packet)]
pub struct UsbPcap {
    pub header_length: u16le,
    pub irp_id: u64le,
    #[construct_with(u32le)]
    pub status: UsbPcapStatus,
    #[construct_with(u16le)]
    pub function: UsbPcapFunction,
    pub reserved_info: u7,
    pub pdo_to_fdo: u1,
    pub bus: u16le,
    pub device: u16le,
    pub direction: u1,
    pub reserved_endpoint: u3,
    pub endpoint: u4,
    pub transfer: u8,
    pub data_length: u32le,
    #[length = "header_length - 27"]
    pub header_payload: Vec<u8>,
    #[length = "data_length"]
    #[payload]
    pub payload: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use pnet_macros_support::packet::Packet;

    #[test]
    fn usbpcap_packet_test() {
        let mut packet = [0u8; 35];
        {
            let mut usbpcap = MutableUsbPcapPacket::new(&mut packet[..]).unwrap();
            usbpcap.set_header_length(27);
            assert_eq!(usbpcap.get_header_length(), 27);

            usbpcap.set_irp_id(0x12_34);
            assert_eq!(usbpcap.get_irp_id(), 0x12_34);

            usbpcap.set_status(UsbPcapStatus(30));
            assert_eq!(usbpcap.get_status(), UsbPcapStatus(30));

            usbpcap.set_function(UsbPcapFunction(40));
            assert_eq!(usbpcap.get_function(), UsbPcapFunction(40));

            assert_eq!(usbpcap.get_reserved_info(), 0);

            usbpcap.set_pdo_to_fdo(1);
            assert_eq!(usbpcap.get_pdo_to_fdo(), 1);

            usbpcap.set_bus(60);
            assert_eq!(usbpcap.get_bus(), 60);

            usbpcap.set_device(70);
            assert_eq!(usbpcap.get_device(), 70);

            usbpcap.set_direction(1);
            assert_eq!(usbpcap.get_direction(), 1);

            assert_eq!(usbpcap.get_reserved_endpoint(), 0);

            usbpcap.set_endpoint(14);
            assert_eq!(usbpcap.get_endpoint(), 14);

            usbpcap.set_transfer(80);
            assert_eq!(usbpcap.get_transfer(), 80);

            usbpcap.set_data_length(2);
            assert_eq!(usbpcap.get_data_length(), 2);

            assert_eq!(usbpcap.get_header_payload(), &[]);

            usbpcap.set_payload(&[90, 100]);
            assert_eq!(usbpcap.payload(), &[90, 100]);
        }

        let ref_packet = [
            27, 0, // Header length
            0x34, 0x12, 0, 0, 0, 0, 0, 0, // IRP ID
            30, 0, 0, 0, // Status
            40, 0, // Function
            1, // Info octet
            60, 0, // Bus
            70, 0, // Device
            142, // Endpoint fields
            80, // Transfer field
            2, 0, 0, 0, // Data length field
            // No header payload
            90, 100 // Payload
        ];

        assert_eq!(&ref_packet[..], &packet[0..29]);
    }

    #[test]
    fn usbpcap_packet_test_variable_header() {
        let mut packet = [0u8; 35];
        {
            let mut usbpcap = MutableUsbPcapPacket::new(&mut packet[..]).unwrap();
            usbpcap.set_header_length(28);
            assert_eq!(usbpcap.get_header_length(), 28);

            usbpcap.set_header_payload(&[110]);
            assert_eq!(usbpcap.get_header_payload(), &[110]);

            assert_eq!(usbpcap.payload(), &[]);
        }

        let ref_packet = [
            28, 0, // Header length
            0, 0, 0, 0, 0, 0, 0, 0, // IRP ID
            0, 0, 0, 0, // Status
            0, 0, // Function
            0, // Info
            0, 0, // Bus
            0, 0, // Device
            0, // Endpoint fields
            0, // Transfer field
            0, 0, 0, 0, // Data length field
            110, // Header payload
            // No payload
        ];

        assert_eq!(&ref_packet[..], &packet[0..28]);
    }
}<|endoftext|>


<commit_before>/* Repeating-key XOR decrypter
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern mod single_xor_lib;

extern mod extra;

#[cfg(not(test))]
use std::path::Path;
#[cfg(not(test))]
use std::io::fs::File;
#[cfg(not(test))]
use std::str;
use std::vec;

use std::iter::AdditiveIterator;

#[cfg(not(test))]
use extra::base64::FromBase64;

#[cfg(not(test))]
use single_xor_lib::decrypt;

// TODO: Rename it or rename the corresponding type in single_xor_lib
#[cfg(not(test))]
enum DecryptionResult {
    Found(~[u8], ~[u8]),
    NotFound
}

/*
 * Calculate Hamming distance between two binary vectors.
 * If vectors have different lengths the smallest length will be used.
 */
fn hamming_distance(s1: &[u8], s2: &[u8]) -> uint {
    static n_bits: [u8, ..256] =
            [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3,
             3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
             3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2,
             2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5,
             3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5,
             5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3,
             2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
             4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
             3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4,
             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
             5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5,
             5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8];
    // Iteration will stop once one of the iterators will stop
    let iter = s1.iter().zip(s2.iter());
    iter.map(|(&c1, &c2)| -> uint n_bits[c1 ^ c2] as uint).sum()
}

/*
 * Guess possible key size for the binary buffer
 */
fn guess_keysize(buffer: &[u8]) -> ~[uint] {
    static max_key_size: uint = 50;

    let len = buffer.len();
    let mut keysizes = vec::with_capacity(max_key_size - 2);

    for s in range(2, max_key_size + 1) {
        let size = s as uint;
        // We're not trying too hard here
        // TODO: Calculate max value outside of the loop and remove this check
        if len < size * 4 {
            break;
        }
        // Calculate average Hamming distance between four pairs of encrypted
        // text
        let d1 = hamming_distance(buffer.slice(0, size),
                                  buffer.slice(size, size * 2));
        let d2 = hamming_distance(buffer.slice(size, size * 2),
                                  buffer.slice(size * 2, size * 3));
        let d3 = hamming_distance(buffer.slice(0, size),
                                  buffer.slice(size * 3, size * 4));
        let d4 = hamming_distance(buffer.slice(size * 2, size * 3),
                                  buffer.slice(size * 3, size * 4));
        let dist: f32 = (d1 + d2 + d3 + d4) as f32 / (4 * size) as f32;
        keysizes.push((dist, size));
    }
    // TODO: Add TotalOrd implementation for f32?
    keysizes.sort_by(|&(d1, _), &(d2, _)| {
            if d1 > d2 {
                Greater
            } else if d1 < d2 {
                Less
            } else {
                Equal
            }
        });
    keysizes.iter().map(|&(_, s)| s).collect()
}

#[cfg(not(test))]
fn decrypt_with_keysize(encrypted: &[u8], keysize: uint) -> DecryptionResult {
    let len = encrypted.len();
    let line_len = (len / keysize) + 1;
    let mut buffers: ~[~[u8]] = vec::from_fn(keysize,
        |_| -> ~[u8] vec::with_capacity(line_len));
    for block in encrypted.chunks(keysize) {
        for (i, &c) in block.iter().enumerate() {
            buffers[i].push(c);
        }
    }
    let mut key: ~[u8] = vec::with_capacity(keysize);
    let mut decrypted: ~[u8] = vec::from_elem(len, 0u8);
    for (i, block) in buffers.iter().enumerate() {
        match decrypt(*block) {
            single_xor_lib::Found(k, text) => {
                key.push(k);
                for (j, &c) in text.iter().enumerate() {
                    decrypted[i + j * keysize] = c;
                }
            },
            single_xor_lib::NotFound => return NotFound
        }
    }
    Found(key, decrypted)
}

#[cfg(not(test))]
fn decrypt_repeating_xor(encrypted: &[u8]) -> DecryptionResult {
    // TODO: It seems we need to try few keysizes here
    match guess_keysize(encrypted) {
        [] => return NotFound,
        // TODO: Key size is 29, key: "Terminator X"
        keysizes => {
            for &keysize in keysizes.iter() {
                let found = decrypt_with_keysize(encrypted, keysize);
                match found {
                    Found(..) => return found,
                    NotFound => ()
                }
            }
        }
    }
    NotFound
}

#[cfg(not(test))]
fn decrypt_repeating_xor_file(mut file: File) -> DecryptionResult {
    let data = file.read_to_end();
    let encrypted = str::from_utf8(data).from_base64().unwrap();
    decrypt_repeating_xor(encrypted)
}

#[cfg(not(test))]
fn main() {
    let path = Path::new("buffer.txt");
    let decrypted = match File::open(&path) {
        Some(file) => decrypt_repeating_xor_file(file),
        None => fail!("Unable to open buffer.txt")
    };
    match decrypted {
        Found(key, text) => println!(
            "Key       => {}\n\
             Decrypted => {}",
            str::from_utf8(key), str::from_utf8(text)),
        NotFound => println!("ERROR: No key found")
    }
}

#[test]
fn test_hamming_distance() {
    let s1 = ~"this is a test";
    let s2 = ~"wokka wokka!!!";
    assert_eq!(hamming_distance(s1.into_bytes(), s2.into_bytes()), 37);
}

#[test]
fn test_guess_keysize() {
    let buffer1 = ~"123456";
    assert_eq!(guess_keysize(buffer1.into_bytes()), ~[]);

    let buffer2 = ~"1234567890123456789012345678901234567890";
    assert_eq!(guess_keysize(buffer2.into_bytes()),
               ~[10u, 4u, 6u, 8u, 2u, 9u, 3u, 7u, 5u]);
}
<commit_msg>Simplify guess_keysize() function<commit_after>/* Repeating-key XOR decrypter
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern mod single_xor_lib;

extern mod extra;

#[cfg(not(test))]
use std::path::Path;
#[cfg(not(test))]
use std::io::fs::File;
#[cfg(not(test))]
use std::str;
use std::vec;

use std::iter::AdditiveIterator;

#[cfg(not(test))]
use extra::base64::FromBase64;

#[cfg(not(test))]
use single_xor_lib::decrypt;

// TODO: Rename it or rename the corresponding type in single_xor_lib
#[cfg(not(test))]
enum DecryptionResult {
    Found(~[u8], ~[u8]),
    NotFound
}

/*
 * Calculate Hamming distance between two binary vectors.
 * If vectors have different lengths the smallest length will be used.
 */
fn hamming_distance(s1: &[u8], s2: &[u8]) -> uint {
    static n_bits: [uint, ..256] =
            [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3,
             3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
             3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2,
             2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5,
             3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5,
             5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3,
             2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
             4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
             3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4,
             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
             5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5,
             5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8];
    // Iteration will stop once one of the iterators will stop
    s1.iter().zip(s2.iter()).map(|(&c1, &c2)| n_bits[c1 ^ c2]).sum()
}

/*
 * Return list of key sizes sorted by probability
 */
fn guess_keysize(buffer: &[u8]) -> ~[uint] {
    static min_block_size: uint = 2;
    static max_block_size: uint = 50;

    let max = match buffer.len() / 4 {
        block_size if block_size <= min_block_size =>
            // Make sure max block size is greater than min block size
            return ~[],
        block_size if block_size > max_block_size =>
            max_block_size,
        block_size =>
            // We're not trying too hard here
            block_size
    };
    let mut keysizes = vec::with_capacity(max - min_block_size);

    for size in range(min_block_size, max + 1) {
        // Calculate average Hamming distance between four consecutive parts of
        // encrypted text
        let s1 = buffer.slice(0, size);
        let s2 = buffer.slice(size, size * 2);
        let s3 = buffer.slice(size * 2, size * 3);
        let s4 = buffer.slice(size * 3, size * 4);
        let d1 = hamming_distance(s1, s2);
        let d2 = hamming_distance(s2, s3);
        let d3 = hamming_distance(s1, s4);
        let d4 = hamming_distance(s3, s4);
        // Calculate average and normalized value of the distance
        let dist: uint = ((d1 + d2 + d3 + d4) * 1000) / (4 * size);
        keysizes.push((dist, size));
    }
    keysizes.sort();
    keysizes.iter().map(|&(_, s)| s).collect()
}

#[cfg(not(test))]
fn decrypt_with_keysize(encrypted: &[u8], keysize: uint) -> DecryptionResult {
    let len = encrypted.len();
    let line_len = (len / keysize) + 1;
    let mut buffers: ~[~[u8]] = vec::from_fn(keysize,
        |_| -> ~[u8] vec::with_capacity(line_len));
    for block in encrypted.chunks(keysize) {
        for (i, &c) in block.iter().enumerate() {
            buffers[i].push(c);
        }
    }
    let mut key: ~[u8] = vec::with_capacity(keysize);
    let mut decrypted: ~[u8] = vec::from_elem(len, 0u8);
    for (i, block) in buffers.iter().enumerate() {
        match decrypt(*block) {
            single_xor_lib::Found(k, text) => {
                key.push(k);
                for (j, &c) in text.iter().enumerate() {
                    decrypted[i + j * keysize] = c;
                }
            },
            single_xor_lib::NotFound => return NotFound
        }
    }
    Found(key, decrypted)
}

#[cfg(not(test))]
fn decrypt_repeating_xor(encrypted: &[u8]) -> DecryptionResult {
    match guess_keysize(encrypted) {
        [] => return NotFound,
        keysizes => {
            for &keysize in keysizes.iter() {
                let found = decrypt_with_keysize(encrypted, keysize);
                match found {
                    Found(..) => return found,
                    NotFound => ()
                }
            }
        }
    }
    NotFound
}

#[cfg(not(test))]
fn decrypt_repeating_xor_file(mut file: File) -> DecryptionResult {
    let data = file.read_to_end();
    let encrypted = str::from_utf8(data).from_base64().unwrap();
    decrypt_repeating_xor(encrypted)
}

#[cfg(not(test))]
fn main() {
    let path = Path::new("buffer.txt");
    let decrypted = match File::open(&path) {
        Some(file) => decrypt_repeating_xor_file(file),
        None => fail!("Unable to open buffer.txt")
    };
    match decrypted {
        Found(key, text) => println!(
            "Key       => {}\n\
             Decrypted => {}",
            str::from_utf8(key), str::from_utf8(text)),
        NotFound => println!("ERROR: No key found")
    }
}

#[test]
fn test_hamming_distance() {
    let s1 = ~"this is a test";
    let s2 = ~"wokka wokka!!!";
    assert_eq!(hamming_distance(s1.into_bytes(), s2.into_bytes()), 37);
}

#[test]
fn test_guess_keysize() {
    let buffer1 = ~"123456";
    assert_eq!(guess_keysize(buffer1.into_bytes()), ~[]);

    let buffer2 = ~"1234567890123456789012345678901234567890";
    assert_eq!(guess_keysize(buffer2.into_bytes()),
               ~[10u, 4u, 6u, 8u, 2u, 9u, 3u, 7u, 5u]);
}
<|endoftext|>


<commit_before>use crate::io::util::DEFAULT_BUF_SIZE;
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};

use pin_project_lite::pin_project;
use std::io::{self, Read};
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{cmp, fmt};

pin_project! {
    /// The `BufReader` struct adds buffering to any reader.
    ///
    /// It can be excessively inefficient to work directly with a [`AsyncRead`]
    /// instance. A `BufReader` performs large, infrequent reads on the underlying
    /// [`AsyncRead`] and maintains an in-memory buffer of the results.
    ///
    /// `BufReader` can improve the speed of programs that make *small* and
    /// *repeated* read calls to the same file or network socket. It does not
    /// help when reading very large amounts at once, or reading just one or a few
    /// times. It also provides no advantage when reading from a source that is
    /// already in memory, like a `Vec<u8>`.
    ///
    /// When the `BufReader` is dropped, the contents of its buffer will be
    /// discarded. Creating multiple instances of a `BufReader` on the same
    /// stream can cause data loss.
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct BufReader<R> {
        #[pin]
        pub(super) inner: R,
        pub(super) buf: Box<[u8]>,
        pub(super) pos: usize,
        pub(super) cap: usize,
    }
}

impl<R: AsyncRead> BufReader<R> {
    /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
    /// but may change in the future.
    pub fn new(inner: R) -> Self {
        Self::with_capacity(DEFAULT_BUF_SIZE, inner)
    }

    /// Creates a new `BufReader` with the specified buffer capacity.
    pub fn with_capacity(capacity: usize, inner: R) -> Self {
        unsafe {
            let mut buffer = Vec::with_capacity(capacity);
            buffer.set_len(capacity);

            {
                // Convert to MaybeUninit
                let b = &mut *(&mut buffer[..] as *mut [u8] as *mut [MaybeUninit<u8>]);
                inner.prepare_uninitialized_buffer(b);
            }
            Self {
                inner,
                buf: buffer.into_boxed_slice(),
                pos: 0,
                cap: 0,
            }
        }
    }

    /// Gets a reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_ref(&self) -> &R {
        &self.inner
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> {
        self.project().inner
    }

    /// Consumes this `BufReader`, returning the underlying reader.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    pub fn into_inner(self) -> R {
        self.inner
    }

    /// Returns a reference to the internally buffered data.
    ///
    /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
    pub fn buffer(&self) -> &[u8] {
        &self.buf[self.pos..self.cap]
    }

    /// Invalidates all data in the internal buffer.
    #[inline]
    fn discard_buffer(self: Pin<&mut Self>) {
        let me = self.project();
        *me.pos = 0;
        *me.cap = 0;
    }
}

impl<R: AsyncRead> AsyncRead for BufReader<R> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // If we don't have any buffered data and we're doing a massive read
        // (larger than our internal buffer), bypass our internal buffer
        // entirely.
        if self.pos == self.cap && buf.len() >= self.buf.len() {
            let res = ready!(self.as_mut().get_pin_mut().poll_read(cx, buf));
            self.discard_buffer();
            return Poll::Ready(res);
        }
        let mut rem = ready!(self.as_mut().poll_fill_buf(cx))?;
        let nread = rem.read(buf)?;
        self.consume(nread);
        Poll::Ready(Ok(nread))
    }

    // we can't skip unconditionally because of the large buffer case in read.
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
        self.inner.prepare_uninitialized_buffer(buf)
    }
}

impl<R: AsyncRead> AsyncBufRead for BufReader<R> {
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        let me = self.project();

        // If we've reached the end of our internal buffer then we need to fetch
        // some more data from the underlying reader.
        // Branch using `>=` instead of the more correct `==`
        // to tell the compiler that the pos..cap slice is always valid.
        if *me.pos >= *me.cap {
            debug_assert!(*me.pos == *me.cap);
            *me.cap = ready!(me.inner.poll_read(cx, me.buf))?;
            *me.pos = 0;
        }
        Poll::Ready(Ok(&me.buf[*me.pos..*me.cap]))
    }

    fn consume(self: Pin<&mut Self>, amt: usize) {
        let me = self.project();
        *me.pos = cmp::min(*me.pos + amt, *me.cap);
    }
}

impl<R: AsyncRead + AsyncWrite> AsyncWrite for BufReader<R> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_pin_mut().poll_write(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_pin_mut().poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_pin_mut().poll_shutdown(cx)
    }
}

impl<R: fmt::Debug> fmt::Debug for BufReader<R> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BufReader")
            .field("reader", &self.inner)
            .field(
                "buffer",
                &format_args!("{}/{}", self.cap - self.pos, self.buf.len()),
            )
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<BufReader<()>>();
    }
}
<commit_msg>io: Forward poll_write_buf on BufReader (#2654)<commit_after>use crate::io::util::DEFAULT_BUF_SIZE;
use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};

use bytes::Buf;
use pin_project_lite::pin_project;
use std::io::{self, Read};
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{cmp, fmt};

pin_project! {
    /// The `BufReader` struct adds buffering to any reader.
    ///
    /// It can be excessively inefficient to work directly with a [`AsyncRead`]
    /// instance. A `BufReader` performs large, infrequent reads on the underlying
    /// [`AsyncRead`] and maintains an in-memory buffer of the results.
    ///
    /// `BufReader` can improve the speed of programs that make *small* and
    /// *repeated* read calls to the same file or network socket. It does not
    /// help when reading very large amounts at once, or reading just one or a few
    /// times. It also provides no advantage when reading from a source that is
    /// already in memory, like a `Vec<u8>`.
    ///
    /// When the `BufReader` is dropped, the contents of its buffer will be
    /// discarded. Creating multiple instances of a `BufReader` on the same
    /// stream can cause data loss.
    #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
    pub struct BufReader<R> {
        #[pin]
        pub(super) inner: R,
        pub(super) buf: Box<[u8]>,
        pub(super) pos: usize,
        pub(super) cap: usize,
    }
}

impl<R: AsyncRead> BufReader<R> {
    /// Creates a new `BufReader` with a default buffer capacity. The default is currently 8 KB,
    /// but may change in the future.
    pub fn new(inner: R) -> Self {
        Self::with_capacity(DEFAULT_BUF_SIZE, inner)
    }

    /// Creates a new `BufReader` with the specified buffer capacity.
    pub fn with_capacity(capacity: usize, inner: R) -> Self {
        unsafe {
            let mut buffer = Vec::with_capacity(capacity);
            buffer.set_len(capacity);

            {
                // Convert to MaybeUninit
                let b = &mut *(&mut buffer[..] as *mut [u8] as *mut [MaybeUninit<u8>]);
                inner.prepare_uninitialized_buffer(b);
            }
            Self {
                inner,
                buf: buffer.into_boxed_slice(),
                pos: 0,
                cap: 0,
            }
        }
    }

    /// Gets a reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_ref(&self) -> &R {
        &self.inner
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying reader.
    ///
    /// It is inadvisable to directly read from the underlying reader.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut R> {
        self.project().inner
    }

    /// Consumes this `BufReader`, returning the underlying reader.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    pub fn into_inner(self) -> R {
        self.inner
    }

    /// Returns a reference to the internally buffered data.
    ///
    /// Unlike `fill_buf`, this will not attempt to fill the buffer if it is empty.
    pub fn buffer(&self) -> &[u8] {
        &self.buf[self.pos..self.cap]
    }

    /// Invalidates all data in the internal buffer.
    #[inline]
    fn discard_buffer(self: Pin<&mut Self>) {
        let me = self.project();
        *me.pos = 0;
        *me.cap = 0;
    }
}

impl<R: AsyncRead> AsyncRead for BufReader<R> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // If we don't have any buffered data and we're doing a massive read
        // (larger than our internal buffer), bypass our internal buffer
        // entirely.
        if self.pos == self.cap && buf.len() >= self.buf.len() {
            let res = ready!(self.as_mut().get_pin_mut().poll_read(cx, buf));
            self.discard_buffer();
            return Poll::Ready(res);
        }
        let mut rem = ready!(self.as_mut().poll_fill_buf(cx))?;
        let nread = rem.read(buf)?;
        self.consume(nread);
        Poll::Ready(Ok(nread))
    }

    // we can't skip unconditionally because of the large buffer case in read.
    unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit<u8>]) -> bool {
        self.inner.prepare_uninitialized_buffer(buf)
    }
}

impl<R: AsyncRead> AsyncBufRead for BufReader<R> {
    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        let me = self.project();

        // If we've reached the end of our internal buffer then we need to fetch
        // some more data from the underlying reader.
        // Branch using `>=` instead of the more correct `==`
        // to tell the compiler that the pos..cap slice is always valid.
        if *me.pos >= *me.cap {
            debug_assert!(*me.pos == *me.cap);
            *me.cap = ready!(me.inner.poll_read(cx, me.buf))?;
            *me.pos = 0;
        }
        Poll::Ready(Ok(&me.buf[*me.pos..*me.cap]))
    }

    fn consume(self: Pin<&mut Self>, amt: usize) {
        let me = self.project();
        *me.pos = cmp::min(*me.pos + amt, *me.cap);
    }
}

impl<R: AsyncRead + AsyncWrite> AsyncWrite for BufReader<R> {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.get_pin_mut().poll_write(cx, buf)
    }

    fn poll_write_buf<B: Buf>(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut B,
    ) -> Poll<io::Result<usize>> {
        self.get_pin_mut().poll_write_buf(cx, buf)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_pin_mut().poll_flush(cx)
    }

    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.get_pin_mut().poll_shutdown(cx)
    }
}

impl<R: fmt::Debug> fmt::Debug for BufReader<R> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BufReader")
            .field("reader", &self.inner)
            .field(
                "buffer",
                &format_args!("{}/{}", self.cap - self.pos, self.buf.len()),
            )
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn assert_unpin() {
        crate::is_unpin::<BufReader<()>>();
    }
}
<|endoftext|>


<commit_before>// Re-exports
pub use kernels::{KernelSelector, KernelSpace, TaskResult};

mod executable;
pub use executable::*;

mod compile;
pub use compile::*;

mod execute;
pub use execute::*;

#[cfg(test)]
mod tests {
    use super::*;
    use codec::CodecTrait;
    use codec_md::MdCodec;
    use eyre::Result;
    use graph::{PlanOptions, PlanOrdering};
    use graph_triples::ResourceInfo;
    use kernels::{Kernel, KernelType};
    use node_address::Slot;
    use node_patch::{Operation, Patch};
    use test_snaps::{
        fixtures,
        insta::{self, assert_json_snapshot},
        snapshot_set_suffix,
    };
    use tokio::sync::mpsc;

    /// Higher level tests of the top level functions in this crate
    #[tokio::test]
    async fn md_articles() -> Result<()> {
        let fixtures = fixtures();

        // So that test results are not dependant upon the the machine the test is run on or how
        // the test is compiled only use built-in kernels
        let kernels: Vec<Kernel> = kernels::available()
            .await?
            .into_iter()
            .filter(|kernel| matches!(kernel.r#type, KernelType::Builtin))
            .collect();

        let mut settings = insta::Settings::clone_current();
        settings.set_prepend_module_to_snapshot(false);
        settings.bind_to_thread();

        for name in ["code.md", "code-relations.md"] {
            let path = fixtures.join("articles").join(name);

            // Load the article
            let mut root = MdCodec::from_path(&path, None).await?;

            // Strip the fixtures path so it does not differ between machines
            let path = path.strip_prefix(&fixtures)?;
            let project = path.parent().unwrap();

            // Compile the article and snapshot the result
            let (patch_sender, mut patch_receiver) = mpsc::unbounded_channel();
            tokio::spawn(async move {
                while let Some(_patch) = patch_receiver.recv().await {
                    // Ignore for this test
                }
            });
            let (addresses, graph) = compile(path, project, &mut root, &patch_sender)?;
            snapshot_set_suffix(&[name, "-compile"].concat(), || {
                assert_json_snapshot!((&addresses, &graph))
            });

            // Generate various execution plans for the article using alternative options
            // and snapshot them all. Always specify `max_concurrency` to avoid differences
            // due to machine (number of CPUs)
            for (suffix, options) in [
                (
                    "appearance",
                    PlanOptions {
                        ordering: PlanOrdering::Appearance,
                        max_concurrency: 10,
                    },
                ),
                (
                    "appearance-concurrency-0",
                    PlanOptions {
                        ordering: PlanOrdering::Appearance,
                        max_concurrency: 0,
                    },
                ),
                (
                    "topological",
                    PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 10,
                    },
                ),
                (
                    "topological-concurrency-0",
                    PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 0,
                    },
                ),
            ] {
                let plan = graph
                    .plan(None, Some(kernels.clone()), Some(options))
                    .await?;
                snapshot_set_suffix(&[name, "-", suffix].concat(), || {
                    assert_json_snapshot!(&plan)
                });
            }

            // Execute the article (with topological execution plan) and snapshot the resultant patches
            let plan = graph
                .plan(
                    None,
                    Some(kernels.clone()),
                    Some(PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 10,
                    }),
                )
                .await?;

            let (resource_info_sender, mut resource_info_receiver) =
                mpsc::channel::<ResourceInfo>(1);
            tokio::spawn(async move {
                while let Some(_resource_info) = resource_info_receiver.recv().await {
                    // Ignore for this test
                }
            });

            let (patch_sender, mut patch_receiver) = mpsc::unbounded_channel::<Patch>();
            let patches = tokio::spawn(async move {
                let mut patches = Vec::new();
                while let Some(mut patch) = patch_receiver.recv().await {
                    // Redact execute time and duration from patch because they will
                    // change across test runs
                    for op in patch.ops.iter_mut() {
                        if let Operation::Add { address, value, .. } = op {
                            if let Some(Slot::Name(name)) = address.back() {
                                if name == "execute_ended" || name == "execute_duration" {
                                    *value = Box::new("<redacted>".to_string());
                                }
                            }
                        }
                    }
                    patches.push(patch);
                }
                patches
            });

            execute(
                &plan,
                &mut root,
                &addresses,
                &resource_info_sender,
                &patch_sender,
                None,
            )
            .await?;

            let patches = patches.await?;
            snapshot_set_suffix(&[name, "-patches"].concat(), || {
                assert_json_snapshot!(&patches);
            });
        }

        Ok(())
    }
}
<commit_msg>test(Node execution): Drop senders to avoid hanging<commit_after>// Re-exports
pub use kernels::{KernelSelector, KernelSpace, TaskResult};

mod executable;
pub use executable::*;

mod compile;
pub use compile::*;

mod execute;
pub use execute::*;

#[cfg(test)]
mod tests {
    use super::*;
    use codec::CodecTrait;
    use codec_md::MdCodec;
    use eyre::Result;
    use graph::{PlanOptions, PlanOrdering};
    use graph_triples::ResourceInfo;
    use kernels::{Kernel, KernelType};
    use node_address::Slot;
    use node_patch::{Operation, Patch};
    use test_snaps::{
        fixtures,
        insta::{self, assert_json_snapshot},
        snapshot_set_suffix,
    };
    use tokio::sync::mpsc;

    /// Higher level tests of the top level functions in this crate
    #[tokio::test]
    async fn md_articles() -> Result<()> {
        let fixtures = fixtures();

        // So that test results are not dependant upon the the machine the test is run on or how
        // the test is compiled only use built-in kernels
        let kernels: Vec<Kernel> = kernels::available()
            .await?
            .into_iter()
            .filter(|kernel| matches!(kernel.r#type, KernelType::Builtin))
            .collect();

        let mut settings = insta::Settings::clone_current();
        settings.set_prepend_module_to_snapshot(false);
        settings.bind_to_thread();

        for name in ["code.md", "code-relations.md"] {
            let path = fixtures.join("articles").join(name);

            // Load the article
            let mut root = MdCodec::from_path(&path, None).await?;

            // Strip the fixtures path so it does not differ between machines
            let path = path.strip_prefix(&fixtures)?;
            let project = path.parent().unwrap();

            // Compile the article and snapshot the result
            let (patch_sender, mut patch_receiver) = mpsc::unbounded_channel();
            tokio::spawn(async move {
                while let Some(_patch) = patch_receiver.recv().await {
                    // Ignore for this test
                }
            });
            let (addresses, graph) = compile(path, project, &mut root, &patch_sender)?;
            snapshot_set_suffix(&[name, "-compile"].concat(), || {
                assert_json_snapshot!((&addresses, &graph))
            });

            // Generate various execution plans for the article using alternative options
            // and snapshot them all. Always specify `max_concurrency` to avoid differences
            // due to machine (number of CPUs)
            for (suffix, options) in [
                (
                    "appearance",
                    PlanOptions {
                        ordering: PlanOrdering::Appearance,
                        max_concurrency: 10,
                    },
                ),
                (
                    "appearance-concurrency-0",
                    PlanOptions {
                        ordering: PlanOrdering::Appearance,
                        max_concurrency: 0,
                    },
                ),
                (
                    "topological",
                    PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 10,
                    },
                ),
                (
                    "topological-concurrency-0",
                    PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 0,
                    },
                ),
            ] {
                let plan = graph
                    .plan(None, Some(kernels.clone()), Some(options))
                    .await?;
                snapshot_set_suffix(&[name, "-", suffix].concat(), || {
                    assert_json_snapshot!(&plan)
                });
            }

            // Execute the article (with topological execution plan) and snapshot the resultant patches
            let plan = graph
                .plan(
                    None,
                    Some(kernels.clone()),
                    Some(PlanOptions {
                        ordering: PlanOrdering::Topological,
                        max_concurrency: 10,
                    }),
                )
                .await?;

            let (resource_info_sender, mut resource_info_receiver) =
                mpsc::channel::<ResourceInfo>(1);
            tokio::spawn(async move {
                while let Some(_resource_info) = resource_info_receiver.recv().await {
                    // Ignore for this test
                }
            });

            let (patch_sender, mut patch_receiver) = mpsc::unbounded_channel::<Patch>();
            let patches = tokio::spawn(async move {
                let mut patches = Vec::new();
                while let Some(mut patch) = patch_receiver.recv().await {
                    // Redact execute time and duration from patch because they will
                    // change across test runs
                    for op in patch.ops.iter_mut() {
                        if let Operation::Add { address, value, .. } = op {
                            if let Some(Slot::Name(name)) = address.back() {
                                if name == "execute_ended" || name == "execute_duration" {
                                    *value = Box::new("<redacted>".to_string());
                                }
                            }
                        }
                    }
                    patches.push(patch);
                }
                patches
            });

            execute(
                &plan,
                &mut root,
                &addresses,
                &resource_info_sender,
                &patch_sender,
                None,
            )
            .await?;

            drop(resource_info_sender);
            drop(patch_sender);

            let patches = patches.await?;
            snapshot_set_suffix(&[name, "-patches"].concat(), || {
                assert_json_snapshot!(&patches);
            });
        }

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


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use quote::Ident;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Rule {
    pub name: Ident,
    pub ty: RuleType,
    pub expr: Expr
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RuleType {
    Normal,
    Silent,
    Atomic,
    CompoundAtomic,
    NonAtomic
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
    Str(String),
    Insens(String),
    Range(String, String),
    Ident(Ident),
    PosPred(Box<Expr>),
    NegPred(Box<Expr>),
    Seq(Box<Expr>, Box<Expr>),
    Choice(Box<Expr>, Box<Expr>),
    Opt(Box<Expr>),
    Rep(Box<Expr>),
    RepOnce(Box<Expr>),
    Push(Box<Expr>)
}

impl Expr {
    pub fn map_top_down<F>(self, mut f: F) -> Expr where F: FnMut(Expr) -> Expr {
        pub fn map_internal<F>(expr: Expr, f: &mut F) -> Expr where F: FnMut(Expr) -> Expr {
            let expr = f(expr);

            match expr {
                // TODO: Use box syntax when it gets stabilized.
                Expr::PosPred(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::RepOnce(mapped)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Push(mapped)
                }
                expr => expr
            }
        }

        map_internal(self, &mut f)
    }

    pub fn map_bottom_up<F>(self, mut f: F) -> Expr where F: FnMut(Expr) -> Expr {
        pub fn map_internal<F>(expr: Expr, f: &mut F) -> Expr where F: FnMut(Expr) -> Expr {
            let mapped = match expr {
                Expr::PosPred(expr) => {
                    // TODO: Use box syntax when it gets stabilized.
                    let mapped = Box::new(f(*expr));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::RepOnce(mapped)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(f(*expr));
                    Expr::Push(mapped)
                }
                expr => expr
            };

            f(mapped)
        }

        map_internal(self, &mut f)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn identity() {
        let expr = Expr::Choice(
            Box::new(Expr::Seq(
                Box::new(Expr::Ident(Ident::new("a"))),
                Box::new(Expr::Str("b".to_owned()))
            )),
            Box::new(Expr::PosPred(
                Box::new(Expr::NegPred(
                    Box::new(Expr::Rep(
                        Box::new(Expr::RepOnce(
                            Box::new(Expr::Opt(
                                Box::new(Expr::Choice(
                                    Box::new(Expr::Insens("c".to_owned())),
                                    Box::new(Expr::Push(
                                        Box::new(Expr::Range("'d'".to_owned(), "'e'".to_owned()))
                                    ))
                                ))
                            ))
                        ))
                    ))
                ))
            ))
        );

        assert_eq!(expr.clone().map_bottom_up(|expr| expr).map_top_down(|expr| expr), expr);
    }
}
<commit_msg>Fixed faulty AST map.<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use quote::Ident;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Rule {
    pub name: Ident,
    pub ty: RuleType,
    pub expr: Expr
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RuleType {
    Normal,
    Silent,
    Atomic,
    CompoundAtomic,
    NonAtomic
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
    Str(String),
    Insens(String),
    Range(String, String),
    Ident(Ident),
    PosPred(Box<Expr>),
    NegPred(Box<Expr>),
    Seq(Box<Expr>, Box<Expr>),
    Choice(Box<Expr>, Box<Expr>),
    Opt(Box<Expr>),
    Rep(Box<Expr>),
    RepOnce(Box<Expr>),
    Push(Box<Expr>)
}

impl Expr {
    pub fn map_top_down<F>(self, mut f: F) -> Expr where F: FnMut(Expr) -> Expr {
        pub fn map_internal<F>(expr: Expr, f: &mut F) -> Expr where F: FnMut(Expr) -> Expr {
            let expr = f(expr);

            match expr {
                // TODO: Use box syntax when it gets stabilized.
                Expr::PosPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            }
        }

        map_internal(self, &mut f)
    }

    pub fn map_bottom_up<F>(self, mut f: F) -> Expr where F: FnMut(Expr) -> Expr {
        pub fn map_internal<F>(expr: Expr, f: &mut F) -> Expr where F: FnMut(Expr) -> Expr {
            let mapped = match expr {
                Expr::PosPred(expr) => {
                    // TODO: Use box syntax when it gets stabilized.
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::PosPred(mapped)
                }
                Expr::NegPred(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::NegPred(mapped)
                }
                Expr::Seq(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Seq(mapped_lhs, mapped_rhs)
                }
                Expr::Choice(lhs, rhs) => {
                    let mapped_lhs = Box::new(map_internal(*lhs, f));
                    let mapped_rhs = Box::new(map_internal(*rhs, f));
                    Expr::Choice(mapped_lhs, mapped_rhs)
                }
                Expr::Rep(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Rep(mapped)
                }
                Expr::RepOnce(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::RepOnce(mapped)
                }
                Expr::Opt(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Opt(mapped)
                }
                Expr::Push(expr) => {
                    let mapped = Box::new(map_internal(*expr, f));
                    Expr::Push(mapped)
                }
                expr => expr
            };

            f(mapped)
        }

        map_internal(self, &mut f)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn identity() {
        let expr = Expr::Choice(
            Box::new(Expr::Seq(
                Box::new(Expr::Ident(Ident::new("a"))),
                Box::new(Expr::Str("b".to_owned()))
            )),
            Box::new(Expr::PosPred(
                Box::new(Expr::NegPred(
                    Box::new(Expr::Rep(
                        Box::new(Expr::RepOnce(
                            Box::new(Expr::Opt(
                                Box::new(Expr::Choice(
                                    Box::new(Expr::Insens("c".to_owned())),
                                    Box::new(Expr::Push(
                                        Box::new(Expr::Range("'d'".to_owned(), "'e'".to_owned()))
                                    ))
                                ))
                            ))
                        ))
                    ))
                ))
            ))
        );

        assert_eq!(expr.clone().map_bottom_up(|expr| expr).map_top_down(|expr| expr), expr);
    }
}
<|endoftext|>


<commit_before>const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Marker {
    FixPos(u8),
    FixNeg(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixStr(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixArray(u8),
    Array16,
    Array32,
    FixMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
    Reserved,
}

impl Marker {
    pub fn from_u8(n: u8) -> Marker {
        match n {
            0x00 ... 0x7f => Marker::FixPos(n),
            0xe0 ... 0xff => Marker::FixNeg(n as i8),
            0x80 ... 0x8f => Marker::FixMap(n & FIXMAP_SIZE),
            0x90 ... 0x9f => Marker::FixArray(n & FIXARRAY_SIZE),
            0xa0 ... 0xbf => Marker::FixStr(n & FIXSTR_SIZE),
            0xc0 => Marker::Null,
            /// Marked in MessagePack spec as never used.
            0xc1 => Marker::Reserved,
            0xc2 => Marker::False,
            0xc3 => Marker::True,
            0xc4 => Marker::Bin8,
            0xc5 => Marker::Bin16,
            0xc6 => Marker::Bin32,
            0xc7 => Marker::Ext8,
            0xc8 => Marker::Ext16,
            0xc9 => Marker::Ext32,
            0xca => Marker::F32,
            0xcb => Marker::F64,
            0xcc => Marker::U8,
            0xcd => Marker::U16,
            0xce => Marker::U32,
            0xcf => Marker::U64,
            0xd0 => Marker::I8,
            0xd1 => Marker::I16,
            0xd2 => Marker::I32,
            0xd3 => Marker::I64,
            0xd4 => Marker::FixExt1,
            0xd5 => Marker::FixExt2,
            0xd6 => Marker::FixExt4,
            0xd7 => Marker::FixExt8,
            0xd8 => Marker::FixExt16,
            0xd9 => Marker::Str8,
            0xda => Marker::Str16,
            0xdb => Marker::Str32,
            0xdc => Marker::Array16,
            0xdd => Marker::Array32,
            0xde => Marker::Map16,
            0xdf => Marker::Map32,
            _ => unreachable!(),
        }
    }

    pub fn to_u8(&self) -> u8 {
        match *self {
            Marker::FixPos(val)   => val,
            Marker::FixNeg(val)   => val as u8,

            Marker::Null          => 0xc0,

            Marker::True          => 0xc3,
            Marker::False         => 0xc2,

            Marker::U8            => 0xcc,
            Marker::U16           => 0xcd,
            Marker::U32           => 0xce,
            Marker::U64           => 0xcf,

            Marker::I8            => 0xd0,
            Marker::I16           => 0xd1,
            Marker::I32           => 0xd2,
            Marker::I64           => 0xd3,

            Marker::F32           => 0xca,
            Marker::F64           => 0xcb,

            Marker::FixStr(len)   => 0xa0 | (len & FIXSTR_SIZE),
            Marker::Str8          => 0xd9,
            Marker::Str16         => 0xda,
            Marker::Str32         => 0xdb,

            Marker::Bin8          => 0xc4,
            Marker::Bin16         => 0xc5,
            Marker::Bin32         => 0xc6,

            Marker::FixArray(len) => 0x90 | (len & FIXARRAY_SIZE),
            Marker::Array16       => 0xdc,
            Marker::Array32       => 0xdd,

            Marker::FixMap(len)   => 0x80 | (len & FIXMAP_SIZE),
            Marker::Map16         => 0xde,
            Marker::Map32         => 0xdf,

            Marker::FixExt1       => 0xd4,
            Marker::FixExt2       => 0xd5,
            Marker::FixExt4       => 0xd6,
            Marker::FixExt8       => 0xd7,
            Marker::FixExt16      => 0xd8,
            Marker::Ext8          => 0xc7,
            Marker::Ext16         => 0xc8,
            Marker::Ext32         => 0xc9,

            Marker::Reserved      => 0xc1,
        }
    }
}

impl From<u8> for Marker {
    fn from(val: u8) -> Marker {
        Marker::from_u8(val)
    }
}

impl Into<u8> for Marker {
    fn into(self) -> u8 {
        self.to_u8()
    }
}
<commit_msg>docs: add some docs<commit_after>const FIXSTR_SIZE   : u8 = 0x1f;
const FIXARRAY_SIZE : u8 = 0x0f;
const FIXMAP_SIZE   : u8 = 0x0f;

/// Format markers.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Marker {
    FixPos(u8),
    FixNeg(i8),
    Null,
    True,
    False,
    U8,
    U16,
    U32,
    U64,
    I8,
    I16,
    I32,
    I64,
    F32,
    F64,
    FixStr(u8),
    Str8,
    Str16,
    Str32,
    Bin8,
    Bin16,
    Bin32,
    FixArray(u8),
    Array16,
    Array32,
    FixMap(u8),
    Map16,
    Map32,
    FixExt1,
    FixExt2,
    FixExt4,
    FixExt8,
    FixExt16,
    Ext8,
    Ext16,
    Ext32,
    Reserved,
}

impl Marker {
    /// Construct a msgpack marker from a single byte.
    pub fn from_u8(n: u8) -> Marker {
        match n {
            0x00 ... 0x7f => Marker::FixPos(n),
            0xe0 ... 0xff => Marker::FixNeg(n as i8),
            0x80 ... 0x8f => Marker::FixMap(n & FIXMAP_SIZE),
            0x90 ... 0x9f => Marker::FixArray(n & FIXARRAY_SIZE),
            0xa0 ... 0xbf => Marker::FixStr(n & FIXSTR_SIZE),
            0xc0 => Marker::Null,
            /// Marked in MessagePack spec as never used.
            0xc1 => Marker::Reserved,
            0xc2 => Marker::False,
            0xc3 => Marker::True,
            0xc4 => Marker::Bin8,
            0xc5 => Marker::Bin16,
            0xc6 => Marker::Bin32,
            0xc7 => Marker::Ext8,
            0xc8 => Marker::Ext16,
            0xc9 => Marker::Ext32,
            0xca => Marker::F32,
            0xcb => Marker::F64,
            0xcc => Marker::U8,
            0xcd => Marker::U16,
            0xce => Marker::U32,
            0xcf => Marker::U64,
            0xd0 => Marker::I8,
            0xd1 => Marker::I16,
            0xd2 => Marker::I32,
            0xd3 => Marker::I64,
            0xd4 => Marker::FixExt1,
            0xd5 => Marker::FixExt2,
            0xd6 => Marker::FixExt4,
            0xd7 => Marker::FixExt8,
            0xd8 => Marker::FixExt16,
            0xd9 => Marker::Str8,
            0xda => Marker::Str16,
            0xdb => Marker::Str32,
            0xdc => Marker::Array16,
            0xdd => Marker::Array32,
            0xde => Marker::Map16,
            0xdf => Marker::Map32,
            _ => unreachable!(),
        }
    }

    /// Converts a marker object into a single-byte representation.
    pub fn to_u8(&self) -> u8 {
        match *self {
            Marker::FixPos(val)   => val,
            Marker::FixNeg(val)   => val as u8,

            Marker::Null          => 0xc0,

            Marker::True          => 0xc3,
            Marker::False         => 0xc2,

            Marker::U8            => 0xcc,
            Marker::U16           => 0xcd,
            Marker::U32           => 0xce,
            Marker::U64           => 0xcf,

            Marker::I8            => 0xd0,
            Marker::I16           => 0xd1,
            Marker::I32           => 0xd2,
            Marker::I64           => 0xd3,

            Marker::F32           => 0xca,
            Marker::F64           => 0xcb,

            Marker::FixStr(len)   => 0xa0 | (len & FIXSTR_SIZE),
            Marker::Str8          => 0xd9,
            Marker::Str16         => 0xda,
            Marker::Str32         => 0xdb,

            Marker::Bin8          => 0xc4,
            Marker::Bin16         => 0xc5,
            Marker::Bin32         => 0xc6,

            Marker::FixArray(len) => 0x90 | (len & FIXARRAY_SIZE),
            Marker::Array16       => 0xdc,
            Marker::Array32       => 0xdd,

            Marker::FixMap(len)   => 0x80 | (len & FIXMAP_SIZE),
            Marker::Map16         => 0xde,
            Marker::Map32         => 0xdf,

            Marker::FixExt1       => 0xd4,
            Marker::FixExt2       => 0xd5,
            Marker::FixExt4       => 0xd6,
            Marker::FixExt8       => 0xd7,
            Marker::FixExt16      => 0xd8,
            Marker::Ext8          => 0xc7,
            Marker::Ext16         => 0xc8,
            Marker::Ext32         => 0xc9,

            Marker::Reserved      => 0xc1,
        }
    }
}

impl From<u8> for Marker {
    fn from(val: u8) -> Marker {
        Marker::from_u8(val)
    }
}

impl Into<u8> for Marker {
    fn into(self) -> u8 {
        self.to_u8()
    }
}
<|endoftext|>


<commit_before>use hir::db::HirDatabase;
use ra_syntax::{algo::non_trivia_sibling, Direction, T};

use crate::{Assist, AssistCtx, AssistId};

pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?;
    let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
    let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;

    // Don't apply a "flip" in case of a last comma
    // that typically comes before punctuation
    if next.kind().is_punct() {
        return None;
    }

    ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
        edit.target(comma.text_range());
        edit.replace(prev.text_range(), next.to_string());
        edit.replace(next.text_range(), prev.to_string());
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use super::*;

    use crate::helpers::{check_assist, check_assist_target};

    #[test]
    fn flip_comma_works_for_function_parameters() {
        check_assist(
            flip_comma,
            "fn foo(x: i32,<|> y: Result<(), ()>) {}",
            "fn foo(y: Result<(), ()>,<|> x: i32) {}",
        )
    }

    #[test]
    fn flip_comma_target() {
        check_assist_target(flip_comma, "fn foo(x: i32,<|> y: Result<(), ()>) {}", ",")
    }

    #[test]
    #[should_panic]
    fn flip_comma_before_punct() {
        // See https://github.com/rust-analyzer/rust-analyzer/issues/1619
        // "Flip comma" assist shouldn't be applicable to the last comma in enum or struct
        // declaration body.
        check_assist_target(flip_comma,
                            "pub enum Test { \
                                A,<|> \
                            }", ",");

        check_assist_target(flip_comma,
                            "pub struct Test { \
                                foo: usize,<|> \
                            }", ",");
    }
}
<commit_msg>rustfmt<commit_after>use hir::db::HirDatabase;
use ra_syntax::{algo::non_trivia_sibling, Direction, T};

use crate::{Assist, AssistCtx, AssistId};

pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == T![,])?;
    let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?;
    let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?;

    // Don't apply a "flip" in case of a last comma
    // that typically comes before punctuation
    if next.kind().is_punct() {
        return None;
    }

    ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
        edit.target(comma.text_range());
        edit.replace(prev.text_range(), next.to_string());
        edit.replace(next.text_range(), prev.to_string());
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use super::*;

    use crate::helpers::{check_assist, check_assist_target};

    #[test]
    fn flip_comma_works_for_function_parameters() {
        check_assist(
            flip_comma,
            "fn foo(x: i32,<|> y: Result<(), ()>) {}",
            "fn foo(y: Result<(), ()>,<|> x: i32) {}",
        )
    }

    #[test]
    fn flip_comma_target() {
        check_assist_target(flip_comma, "fn foo(x: i32,<|> y: Result<(), ()>) {}", ",")
    }

    #[test]
    #[should_panic]
    fn flip_comma_before_punct() {
        // See https://github.com/rust-analyzer/rust-analyzer/issues/1619
        // "Flip comma" assist shouldn't be applicable to the last comma in enum or struct
        // declaration body.
        check_assist_target(
            flip_comma,
            "pub enum Test { \
             A,<|> \
             }",
            ",",
        );

        check_assist_target(
            flip_comma,
            "pub struct Test { \
             foo: usize,<|> \
             }",
            ",",
        );
    }
}
<|endoftext|>


<commit_before>use std::{
    fs,
    path::{Path, PathBuf},
};

use binary_node::{Binary, BinaryTrait, NodeBinary};
use buildpack::{
    eyre::{self, bail},
    fs_utils::{copy_dir_all, symlink_dir, symlink_file},
    libcnb::{
        self,
        build::{BuildContext, BuildResult, BuildResultBuilder},
        data::{build_plan::BuildPlan, layer_content_metadata::LayerTypes, layer_name},
        detect::{DetectContext, DetectResult, DetectResultBuilder},
        generic::{GenericMetadata, GenericPlatform},
        layer::{Layer, LayerResult, LayerResultBuilder},
        layer_env::{LayerEnv, ModificationBehavior, Scope},
        Buildpack,
    },
    platform_is_stencila, BuildpackTrait,
};

pub struct NodeBuildpack;

impl BuildpackTrait for NodeBuildpack {
    fn toml() -> &'static str {
        include_str!("../buildpack.toml")
    }
}

impl Buildpack for NodeBuildpack {
    type Platform = GenericPlatform;
    type Metadata = GenericMetadata;
    type Error = eyre::Report;

    fn detect(&self, _context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> {
        // Read `.tool-versions` for Node.js version
        const TOOL_VERSIONS: &str = ".tool-versions";
        let tool_versions = Self::tool_versions();

        // Read `.nvmrc` for Node.js version
        const NVMRC: &str = ".nvmrc";
        let nvmrc = fs::read_to_string(NVMRC)
            .map(|content| content.trim().to_string())
            .ok();

        // Read `package.json` for Node.js version
        const PACKAGE_JSON: &str = "package.json";
        let package_json = fs::read_to_string(PACKAGE_JSON)
            .ok()
            .and_then(|json| serde_json::from_str::<serde_json::Value>(&json).ok());

        // Detect `package-lock.json`
        const PACKAGE_LOCK: &str = "package-lock.json";
        let package_lock = PathBuf::from(PACKAGE_LOCK);

        // Fail early
        if !(tool_versions.contains_key("nodejs")
            || tool_versions.contains_key("node")
            || package_json.is_some()
            || package_lock.exists()
            || nvmrc.is_some()
            || Self::any_exist(&["main.js", "index.js"]))
        {
            return DetectResultBuilder::fail().build();
        }

        let mut requires = Vec::new();
        let mut provides = Vec::new();

        // Resolve Node.js version from `.tool-versions`, `.nvmrc` or `package.json`
        let (version, source) = if let Some(version) = tool_versions
            .get("nodejs")
            .or_else(|| tool_versions.get("node"))
        {
            (version.to_string(), TOOL_VERSIONS)
        } else if let Some(versionish) = nvmrc {
            (versionish, NVMRC)
        } else if let Some(semver) = package_json.as_ref().and_then(|package| {
            package
                .pointer("/engines/node")
                .and_then(|semver| semver.as_str().map(|semver| semver.to_string()))
        }) {
            (semver, PACKAGE_JSON)
        } else {
            (String::new(), "")
        };

        // Require and provide Node.js
        let (require, provide) = Self::require_and_provide(
            format!("node {}", version),
            source,
            format!("Install Node.js {}", version),
        );
        requires.push(require);
        provides.push(provide);

        // Determine how NPM packages are to be installed
        if package_lock.exists() || package_json.is_some() {
            let (require, provide) = Self::require_and_provide(
                "npm install",
                if package_lock.exists() {
                    PACKAGE_LOCK
                } else {
                    PACKAGE_JSON
                },
                "Install NPM packages using `npm install`",
            );
            requires.push(require);
            provides.push(provide);
        }

        let mut build_plan = BuildPlan::new();
        build_plan.requires = requires;
        build_plan.provides = provides;
        DetectResultBuilder::pass().build_plan(build_plan).build()
    }

    fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
        let entries: Vec<String> = context
            .buildpack_plan
            .entries
            .iter()
            .map(|entry| entry.name.clone())
            .collect();

        for entry in entries {
            let (name, args) = Self::split_entry_name(&entry);
            match name.as_str() {
                "node" => {
                    context.handle_layer(layer_name!("node"), NodeLayer::new(args))?;
                }
                "npm" => {
                    context.handle_layer(layer_name!("npm"), NpmLayer::new(args))?;
                }
                _ => (),
            };
        }

        BuildResultBuilder::new().build()
    }
}

struct NodeLayer {
    /// A string describing the version, of Node.js to install
    ///
    /// This could be a well formed semantic version (e.g 14.0.1),
    /// a semver requirement (e.g. ^14.0), or an alias (e.g. `lts`).
    /// The `create` method aim to convert them all to a semver requirement.
    versionish: String,
}

impl NodeLayer {
    fn new(args: Vec<String>) -> Self {
        NodeLayer {
            // Join args with commas because semver requirement parser expects it to be so
            versionish: args.join(","),
        }
    }
}

impl Layer for NodeLayer {
    type Buildpack = NodeBuildpack;
    type Metadata = GenericMetadata;

    fn types(&self) -> LayerTypes {
        LayerTypes {
            build: true,
            launch: true,
            cache: true,
        }
    }

    fn create(
        &self,
        context: &BuildContext<Self::Buildpack>,
        layer_path: &Path,
    ) -> Result<LayerResult<Self::Metadata>, eyre::Report> {
        // Determine the semver requirement
        let mut requirement = if let Some(version) = self.versionish.strip_prefix('v') {
            version.to_string()
        } else if self.versionish == "lts" {
            // TODO: Determine LTS without doing a fetch, perhaps based on date
            // https://nodejs.org/en/about/releases/
            "^16".to_string()
        } else {
            self.versionish.clone()
        };
        if requirement.is_empty() {
            requirement = "*".to_string();
        }

        // Ensure a version meeting the semver is installed
        let node = NodeBinary {}.require_sync(Some(requirement), true)?;

        // Symlink/copy the installation into the layer
        let dest = layer_path.join(node.version()?);
        if platform_is_stencila(&context.platform) {
            if node.is_stencila_install() {
                let source = node.grandparent()?;
                symlink_dir(source, &dest)?;
            } else {
                let source = node.parent()?;
                fs::create_dir_all(&dest)?;
                symlink_file(node.path, dest.join(node.name))?;
                symlink_file(source.join("npm"), dest.join("npm"))?;
                symlink_file(source.join("npx"), dest.join("npx"))?;
            }
        } else {
            #[allow(clippy::collapsible_else_if)]
            if node.is_stencila_install() {
                let source = node.grandparent()?;
                copy_dir_all(source, &dest)?;
            } else {
                bail!("Only able to build `node` layer if it has been installed by Stencila")
            }
        }

        LayerResultBuilder::new(GenericMetadata::default()).build()
    }
}

struct NpmLayer;

impl NpmLayer {
    fn new(_args: Vec<String>) -> Self {
        NpmLayer
    }
}

impl Layer for NpmLayer {
    type Buildpack = NodeBuildpack;
    type Metadata = GenericMetadata;

    fn types(&self) -> LayerTypes {
        // Layer is available at build time and is cached but is not needed for
        // launch time because packages are installed into the `node_modules` of the
        // working directory
        LayerTypes {
            build: true,
            launch: false,
            cache: true,
        }
    }

    fn create(
        &self,
        context: &BuildContext<Self::Buildpack>,
        layer_path: &Path,
    ) -> Result<LayerResult<Self::Metadata>, eyre::Report> {
        // Require npm
        // TODO: Should we use a specific version of npm? The version installed by this pack?
        // Or one with expected behavior wrt to package-lock.json, peerDependencies etc.
        let mut npm = Binary::unregistered("npm").require_sync(None, false)?;

        // If this is not a local build then make the layer the NPM cache
        if !platform_is_stencila(&context.platform) {
            npm.set_env(&[("NPM_CONFIG_CACHE", layer_path.canonicalize()?.as_os_str())]);
        }

        // Do the install
        npm.run_sync(&["install"])?;

        LayerResultBuilder::new(GenericMetadata::default()).build()
    }
}
<commit_msg>chore(Node buildpack): Linting<commit_after>use std::{
    fs,
    path::{Path, PathBuf},
};

use binary_node::{Binary, BinaryTrait, NodeBinary};
use buildpack::{
    eyre::{self, bail},
    fs_utils::{copy_dir_all, symlink_dir, symlink_file},
    libcnb::{
        self,
        build::{BuildContext, BuildResult, BuildResultBuilder},
        data::{build_plan::BuildPlan, layer_content_metadata::LayerTypes, layer_name},
        detect::{DetectContext, DetectResult, DetectResultBuilder},
        generic::{GenericMetadata, GenericPlatform},
        layer::{Layer, LayerResult, LayerResultBuilder},
        Buildpack,
    },
    platform_is_stencila, BuildpackTrait,
};

pub struct NodeBuildpack;

impl BuildpackTrait for NodeBuildpack {
    fn toml() -> &'static str {
        include_str!("../buildpack.toml")
    }
}

impl Buildpack for NodeBuildpack {
    type Platform = GenericPlatform;
    type Metadata = GenericMetadata;
    type Error = eyre::Report;

    fn detect(&self, _context: DetectContext<Self>) -> libcnb::Result<DetectResult, Self::Error> {
        // Read `.tool-versions` for Node.js version
        const TOOL_VERSIONS: &str = ".tool-versions";
        let tool_versions = Self::tool_versions();

        // Read `.nvmrc` for Node.js version
        const NVMRC: &str = ".nvmrc";
        let nvmrc = fs::read_to_string(NVMRC)
            .map(|content| content.trim().to_string())
            .ok();

        // Read `package.json` for Node.js version
        const PACKAGE_JSON: &str = "package.json";
        let package_json = fs::read_to_string(PACKAGE_JSON)
            .ok()
            .and_then(|json| serde_json::from_str::<serde_json::Value>(&json).ok());

        // Detect `package-lock.json`
        const PACKAGE_LOCK: &str = "package-lock.json";
        let package_lock = PathBuf::from(PACKAGE_LOCK);

        // Fail early
        if !(tool_versions.contains_key("nodejs")
            || tool_versions.contains_key("node")
            || package_json.is_some()
            || package_lock.exists()
            || nvmrc.is_some()
            || Self::any_exist(&["main.js", "index.js"]))
        {
            return DetectResultBuilder::fail().build();
        }

        let mut requires = Vec::new();
        let mut provides = Vec::new();

        // Resolve Node.js version from `.tool-versions`, `.nvmrc` or `package.json`
        let (version, source) = if let Some(version) = tool_versions
            .get("nodejs")
            .or_else(|| tool_versions.get("node"))
        {
            (version.to_string(), TOOL_VERSIONS)
        } else if let Some(versionish) = nvmrc {
            (versionish, NVMRC)
        } else if let Some(semver) = package_json.as_ref().and_then(|package| {
            package
                .pointer("/engines/node")
                .and_then(|semver| semver.as_str().map(|semver| semver.to_string()))
        }) {
            (semver, PACKAGE_JSON)
        } else {
            (String::new(), "")
        };

        // Require and provide Node.js
        let (require, provide) = Self::require_and_provide(
            format!("node {}", version),
            source,
            format!("Install Node.js {}", version),
        );
        requires.push(require);
        provides.push(provide);

        // Determine how NPM packages are to be installed
        if package_lock.exists() || package_json.is_some() {
            let (require, provide) = Self::require_and_provide(
                "npm install",
                if package_lock.exists() {
                    PACKAGE_LOCK
                } else {
                    PACKAGE_JSON
                },
                "Install NPM packages using `npm install`",
            );
            requires.push(require);
            provides.push(provide);
        }

        let mut build_plan = BuildPlan::new();
        build_plan.requires = requires;
        build_plan.provides = provides;
        DetectResultBuilder::pass().build_plan(build_plan).build()
    }

    fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
        let entries: Vec<String> = context
            .buildpack_plan
            .entries
            .iter()
            .map(|entry| entry.name.clone())
            .collect();

        for entry in entries {
            let (name, args) = Self::split_entry_name(&entry);
            match name.as_str() {
                "node" => {
                    context.handle_layer(layer_name!("node"), NodeLayer::new(args))?;
                }
                "npm" => {
                    context.handle_layer(layer_name!("npm"), NpmLayer::new(args))?;
                }
                _ => (),
            };
        }

        BuildResultBuilder::new().build()
    }
}

struct NodeLayer {
    /// A string describing the version, of Node.js to install
    ///
    /// This could be a well formed semantic version (e.g 14.0.1),
    /// a semver requirement (e.g. ^14.0), or an alias (e.g. `lts`).
    /// The `create` method aim to convert them all to a semver requirement.
    versionish: String,
}

impl NodeLayer {
    fn new(args: Vec<String>) -> Self {
        NodeLayer {
            // Join args with commas because semver requirement parser expects it to be so
            versionish: args.join(","),
        }
    }
}

impl Layer for NodeLayer {
    type Buildpack = NodeBuildpack;
    type Metadata = GenericMetadata;

    fn types(&self) -> LayerTypes {
        LayerTypes {
            build: true,
            launch: true,
            cache: true,
        }
    }

    fn create(
        &self,
        context: &BuildContext<Self::Buildpack>,
        layer_path: &Path,
    ) -> Result<LayerResult<Self::Metadata>, eyre::Report> {
        // Determine the semver requirement
        let mut requirement = if let Some(version) = self.versionish.strip_prefix('v') {
            version.to_string()
        } else if self.versionish == "lts" {
            // TODO: Determine LTS without doing a fetch, perhaps based on date
            // https://nodejs.org/en/about/releases/
            "^16".to_string()
        } else {
            self.versionish.clone()
        };
        if requirement.is_empty() {
            requirement = "*".to_string();
        }

        // Ensure a version meeting the semver is installed
        let node = NodeBinary {}.require_sync(Some(requirement), true)?;

        // Symlink/copy the installation into the layer
        let dest = layer_path.join(node.version()?);
        if platform_is_stencila(&context.platform) {
            if node.is_stencila_install() {
                let source = node.grandparent()?;
                symlink_dir(source, &dest)?;
            } else {
                let source = node.parent()?;
                fs::create_dir_all(&dest)?;
                symlink_file(node.path, dest.join(node.name))?;
                symlink_file(source.join("npm"), dest.join("npm"))?;
                symlink_file(source.join("npx"), dest.join("npx"))?;
            }
        } else {
            #[allow(clippy::collapsible_else_if)]
            if node.is_stencila_install() {
                let source = node.grandparent()?;
                copy_dir_all(source, &dest)?;
            } else {
                bail!("Only able to build `node` layer if it has been installed by Stencila")
            }
        }

        LayerResultBuilder::new(GenericMetadata::default()).build()
    }
}

struct NpmLayer;

impl NpmLayer {
    fn new(_args: Vec<String>) -> Self {
        NpmLayer
    }
}

impl Layer for NpmLayer {
    type Buildpack = NodeBuildpack;
    type Metadata = GenericMetadata;

    fn types(&self) -> LayerTypes {
        // Layer is available at build time and is cached but is not needed for
        // launch time because packages are installed into the `node_modules` of the
        // working directory
        LayerTypes {
            build: true,
            launch: false,
            cache: true,
        }
    }

    fn create(
        &self,
        context: &BuildContext<Self::Buildpack>,
        layer_path: &Path,
    ) -> Result<LayerResult<Self::Metadata>, eyre::Report> {
        // Require npm
        // TODO: Should we use a specific version of npm? The version installed by this pack?
        // Or one with expected behavior wrt to package-lock.json, peerDependencies etc.
        let mut npm = Binary::unregistered("npm").require_sync(None, false)?;

        // If this is not a local build then make the layer the NPM cache
        if !platform_is_stencila(&context.platform) {
            npm.set_env(&[("NPM_CONFIG_CACHE", layer_path.canonicalize()?.as_os_str())]);
        }

        // Do the install
        npm.run_sync(&["install"])?;

        LayerResultBuilder::new(GenericMetadata::default()).build()
    }
}
<|endoftext|>


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

//! A sample plugin, intended as an illustartion and a template for plugin
//! developers.

extern crate xi_plugin_lib;
extern crate xi_core_lib as xi_core;
extern crate xi_rope;

use std::path::Path;

use xi_core::ConfigTable;
use xi_core::plugin_rpc::PluginEdit;
use xi_rope::rope::RopeDelta;
use xi_plugin_lib::{Plugin, ChunkCache, View, mainloop};

struct SamplePlugin;

// implementing the `Plugin` trait is the sole requirement of a plugin.
// For more documentation, see `rust/plugin-lib` in this repo.
impl Plugin for SamplePlugin {
    type Cache = ChunkCache;

    fn new_view(&mut self, view: &mut View<Self::Cache>) {
        eprintln!("new view {}", view.get_id());
    }

    fn did_close(&mut self, view: &View<Self::Cache>) {
        eprintln!("close view {}", view.get_id());
    }

    fn did_save(&mut self, view: &mut View<Self::Cache>, _old: Option<&Path>) {
        eprintln!("saved view {}", view.get_id());
    }

    fn config_changed(&mut self, _view: &mut View<Self::Cache>, _changes: &ConfigTable) {
    }

    fn update(&mut self, view: &mut View<Self::Cache>, _delta: Option<&RopeDelta>,
              _edit_type: String, _author: String) -> Option<PluginEdit> {
        eprintln!("edit in view {}", view.get_id());
        None
    }
}

fn main() {
    let mut plugin = SamplePlugin;
    mainloop(&mut plugin).unwrap();
}
<commit_msg>Sample plugin sends edits<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A sample plugin, intended as an illustration and a template for plugin
//! developers.

extern crate xi_plugin_lib;
extern crate xi_core_lib as xi_core;
extern crate xi_rope;

use std::path::Path;

use xi_core::ConfigTable;
use xi_rope::rope::RopeDelta;
use xi_rope::interval::Interval;
use xi_rope::delta::Builder as EditBuilder;
use xi_plugin_lib::{Plugin, ChunkCache, View, mainloop, Error};

/// A type that implements the `Plugin` trait, and interacts with xi-core.
///
/// Currently, this plugin has a single noteworthy behaviour,
/// intended to demonstrate how to edit a document; when the plugin is active,
/// and the user inserts an exclamation mark, the plugin will capitalize the
/// preceding word.
struct SamplePlugin;

//NOTE: implementing the `Plugin` trait is the sole requirement of a plugin.
// For more documentation, see `rust/plugin-lib` in this repo.
impl Plugin for SamplePlugin {
    type Cache = ChunkCache;

    fn new_view(&mut self, view: &mut View<Self::Cache>) {
        eprintln!("new view {}", view.get_id());
    }

    fn did_close(&mut self, view: &View<Self::Cache>) {
        eprintln!("close view {}", view.get_id());
    }

    fn did_save(&mut self, view: &mut View<Self::Cache>, _old: Option<&Path>) {
        eprintln!("saved view {}", view.get_id());
    }

    fn config_changed(&mut self, _view: &mut View<Self::Cache>, _changes: &ConfigTable) {
    }

    fn update(&mut self, view: &mut View<Self::Cache>, delta: Option<&RopeDelta>,
              _edit_type: String, _author: String) {

        //NOTE: example simple conditional edit. If this delta is
        //an insert of a single '!', we capitalize the preceding word.

        if let Some(delta) = delta {
            let (iv, _) = delta.summary();
            let text: String = delta.as_simple_insert()
                .map(String::from)
                .unwrap_or_default();
            if text == "!" {
                let _ = self.capitalize_word(view, iv.end());
            }
        }
    }
}

impl SamplePlugin {
    /// Uppercases the word preceding `end_offset`.
    fn capitalize_word(&self, view: &mut View<ChunkCache>, end_offset: usize)
        -> Result<(), Error>
    {
        //NOTE: this makes it clear to me that we need a better API for edits
        let line_nb = view.line_of_offset(end_offset)?;
        let line_start = view.offset_of_line(line_nb)?;

        let mut cur_utf8_ix = 0;
        let mut word_start = 0;
        for c in view.get_line(line_nb)?.chars() {
            if c.is_whitespace() {
                word_start = cur_utf8_ix;
            }

            cur_utf8_ix += c.len_utf8();

            if line_start + cur_utf8_ix == end_offset {
                break;
            }
        }

        let new_text = view.get_line(line_nb)?[word_start..end_offset-line_start]
            .to_uppercase();
        let buf_size = view.get_buf_size();
        let mut builder = EditBuilder::new(buf_size);
        let iv = Interval::new_closed_open(line_start + word_start, end_offset);
        builder.replace(iv, new_text.into());
        view.edit(builder.build(), 0, false, true, "sample".into());
        Ok(())
    }
}

fn main() {
    let mut plugin = SamplePlugin;
    mainloop(&mut plugin).unwrap();
}
<|endoftext|>