<commit_before>extern crate av_data;
extern crate av_format;
extern crate circular;
extern crate matroska;
extern crate nom;
extern crate pretty_env_logger;

use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};

fn main() {
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head (size {}) {} elements", b.data().offset(i), s.positions.len());
                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment Information");
                    println!("| + timestamp scale: {}", i.timecode_scale);
                    println!("| + multiplexing application: {}", i.muxing_app);
                    println!("| + writing application: {}", i.writing_app);
                    println!(
                        "| + segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   timecode: {}", c.timecode);
                    println!("|+   silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   position: {:?}", c.position);
                    println!("|+   prev_size: {:?}", c.prev_size);
                    println!("|+   simple_block: {} elements", c.simple_block.len());
                    println!("|+   block_group: {} elements", c.block_group.len());
                    println!(
                        "|+   encrypted_block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<commit_msg>Display individual seek elements, match capitalization, start pos + size<commit_after>extern crate av_data;
extern crate av_format;
extern crate circular;
extern crate matroska;
extern crate nom;
extern crate pretty_env_logger;

use circular::Buffer;
use nom::{Err, Offset};
use std::env;
use std::fs::File;
use std::io::Read;

use matroska::ebml::ebml_header;
use matroska::elements::{segment, segment_element, SegmentElement};
use matroska::serializer::ebml::EbmlSize;

fn main() {
    pretty_env_logger::init();
    let mut args = env::args();
    let _ = args.next().expect("first arg is program path");
    let filename = args.next().expect("expected file path");

    //println!("filename: {}", filename);
    run(&filename).expect("should parse file correctly");
}

fn run(filename: &str) -> std::io::Result<()> {
    let mut file = File::open(filename)?;

    let capacity = 5242880;
    let mut b = Buffer::with_capacity(capacity);

    // we write into the `&mut[u8]` returned by `space()`
    let sz = file.read(b.space()).expect("should write");
    b.fill(sz);
    //eprintln!("write {:#?}", sz);

    let length = {
        let res = ebml_header(b.data());
        if let Ok((remaining, header)) = res {
            //eprintln!("parsed header: {:#?}", h);
            println!("+ EBML head");
            println!("|+ EBML version: {}", header.version);
            println!("|+ EBML read version: {}", header.read_version);
            println!("|+ EBML maximum ID length: {}", header.max_id_length);
            println!("|+ EBML maximum size length: {}", header.max_size_length);
            println!("|+ Doc type: {}", header.doc_type);
            println!("|+ Doc type read version: {}", header.doc_type_read_version);

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    let mut _consumed = length;
    b.consume(length);

    let length = {
        let res = segment(b.data());
        if let Ok((remaining, segment)) = res {
            //eprintln!("parsed segment: {:#?}", h);
            println!("+ Segment, size {}", segment.1.unwrap_or(0));

            b.data().offset(remaining)
        } else {
            panic!("couldn't parse header");
        }
    };

    b.consume(length);

    // handle first elements
    let mut seek_head = None;
    let mut info = None;
    let mut tracks = None;

    loop {
        if seek_head.is_some() && info.is_some() && tracks.is_some() {
            break;
        }

        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            panic!("no more data to read or parse, stopping the reading loop");
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_i)) => continue,
            };

            match element {
                SegmentElement::SeekHead(s) => {
                    println!("|+ Seek head at {:#0x} size {}", 0x0, b.data().offset(i));
                    for seek in s.positions.iter() {
                        let id: u64 = ((seek.id[0] as u64) << 24) |
                            ((seek.id[1] as u64) << 16) |
                            ((seek.id[2] as u64) << 8) |
                            seek.id[3] as u64;

                        let element_size = seek.size(0x4DBB);
                        let id_size = seek.id.size(0x53AB);
                        let position_size = seek.position.size(0x53AC);

                        println!("| + Seek entry size {}", element_size);

                        print!("|  + Seek ID:");
                        for id in seek.id.iter() {
                            print!(" {:#0x}", id);
                        }

                        let name = match &seek.id[..] {
                            [0x11, 0x4D, 0x9B, 0x74] => " (KaxSeekHead)",
                            [0x12, 0x54, 0xC3, 0x67] => " (KaxTags)",
                            [0x15, 0x49, 0xA9, 0x66] => " (KaxInfo)",
                            [0x16, 0x54, 0xAE, 0x6B] => " (KaxTracks)",
                            [0x1C, 0x53, 0xBB, 0x6B] => " (KaxCues)",
                            [0x1F, 0x43, 0xB6, 0x75] => " (KaxCluster)",
                            _ => "",
                        };

                        println!("{} at {:#0x} size {}", name, 0x0, id_size);
                        println!("|  + Seek position: {} size {}", seek.position, position_size);
                    }

                    if seek_head.is_some() {
                        panic!("already got a SeekHead element");
                    } else {
                        seek_head = Some(s);
                    }
                }
                SegmentElement::Info(i) => {
                    println!("|+ Segment information");
                    println!("| + Timestamp scale: {}", i.timecode_scale);
                    println!("| + Multiplexing application: {}", i.muxing_app);
                    println!("| + Writing application: {}", i.writing_app);
                    println!(
                        "| + Segment UID: {:?}",
                        i.segment_uid.as_ref().unwrap_or(&Vec::new())
                    );
                    println!("| + Duration: {}s", i.duration.unwrap_or(0f64) / 1000f64);
                    if info.is_some() {
                        panic!("already got an Info element");
                    } else {
                        info = Some(i);
                    }
                }
                SegmentElement::Tracks(t) => {
                    //eprintln!("got tracks: {:#?}", t);
                    println!("|+ Segment tracks");
                    for tr in t.tracks.iter() {
                        println!("| + A track");
                        println!("|  + Track number: {}", tr.track_number);
                        println!("|  + Track UID: {}", tr.track_uid);
                        println!("|  + Track type: {}", tr.track_type);
                        println!("|  + Lacing flag: {}", tr.flag_lacing.unwrap_or(0));
                        println!("|  + Default flag: {}", tr.flag_default.unwrap_or(0));
                        println!(
                            "|  + Language: {}",
                            tr.language.as_ref().unwrap_or(&"".to_string())
                        );
                        println!("|  + Codec ID: {}", tr.codec_id);
                        println!(
                            "|  + Codec private: length {}",
                            tr.codec_private.as_ref().map(|v| v.len()).unwrap_or(0)
                        );

                        if let Some(ref v) = tr.video {
                            println!("|  + Video track");
                            println!("|    + Pixel width: {}", v.pixel_width);
                            println!("|    + Pixel height: {}", v.pixel_height);
                            if let Some(inter) = v.flag_interlaced {
                                println!("|    + Interlaced: {}", inter);
                            }
                            if let Some(width) = v.display_width {
                                println!("|    + Display width: {}", width);
                            }
                            if let Some(height) = v.display_height {
                                println!("|    + Display height: {}", height);
                            }
                            if let Some(unit) = v.display_unit {
                                println!("|    + Display unit: {}", unit);
                            }
                        }

                        if let Some(ref a) = tr.audio {
                            println!("|  + Audio track");
                            println!("|    + Sampling frequency: {}", a.sampling_frequency);
                            if let Some(frequency) = a.output_sampling_frequency {
                                println!("|    + Output sampling freqeuncy: {}", frequency);
                            }
                            println!("|    + Channels: {}", a.channels);
                            if let Some(ref channel_positions) = a.channel_positions {
                                println!("|    + Channel position: {:?}", channel_positions);
                            }
                            if let Some(bit_depth) = a.bit_depth {
                                println!("|    + Bit depth: {}", bit_depth);
                            }
                        }
                    }
                    if tracks.is_some() {
                        panic!("already got a Tracks element");
                    } else {
                        tracks = Some(t);
                    }
                }
                /*SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    eprintln!("got a cluster: {:#?}", c);
                },*/
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    loop {
        if b.available_space() == 0 {
            b.shift();
            if b.available_space() == 0 {
                println!("buffer is already full,  cannot refill");
                break;
            }
        }

        // refill the buffer
        let sz = file.read(b.space()).expect("should read");
        b.fill(sz);

        /*
        eprintln!(
            "refill: {} more bytes, available data: {} bytes, consumed: {} bytes",
            sz,
            b.available_data(),
            consumed
        );
        */

        // if there's no more available data in the buffer after a write, that means we reached
        // the end of the file
        if b.available_data() == 0 {
            //panic!("no more data to read or parse, stopping the reading loop");
            break;
        }

        let offset = {
            let (i, element) = match segment_element(b.data()) {
                Ok((i, o)) => (i, o),
                Err(Err::Error(e)) | Err(Err::Failure(e)) => panic!("failed parsing: {:?}", e),
                Err(Err::Incomplete(_)) => continue,
            };

            match element {
                SegmentElement::SeekHead(_)
                | SegmentElement::Info(_)
                | SegmentElement::Tracks(_) => {
                    panic!(
                        "unexpected seek head, info or tracks element: {:?}",
                        element
                    );
                }
                SegmentElement::Cluster(c) => {
                    println!("|+ Cluster");
                    println!("|+   Timecode: {}", c.timecode);
                    println!("|+   Silent_tracks: {:?}", c.silent_tracks);
                    println!("|+   Position: {:?}", c.position);
                    println!("|+   Prev size: {:?}", c.prev_size);
                    println!("|+   Simple block: {} elements", c.simple_block.len());
                    println!("|+   Block group: {} elements", c.block_group.len());
                    println!(
                        "|+   Encrypted block: {:?} bytes",
                        c.encrypted_block.as_ref().map(|s| s.len())
                    );
                    //eprintln!("got a cluster: {:#?}", c);
                }
                SegmentElement::Void(s) => {
                    println!("|+ EbmlVoid (size: {})", s);
                }
                SegmentElement::Tags(_) => {
                    println!("|+ Tags");
                }
                SegmentElement::Cues(_) => {
                    println!("|+ Cues");
                }
                SegmentElement::Unknown(id, data) => {
                    panic!(
                        "offset {:X?}: got unknown element: {:X?} {:#?}",
                        _consumed, id, data
                    );
                }
                el => {
                    panic!("got unexpected element: {:#?}", el);
                }
            }

            b.data().offset(i)
        };
        _consumed += offset;
        //eprintln!("consumed {} bytes", length);
        b.consume(offset);
    }

    Ok(())
}
<|endoftext|>


<commit_before>fn get_sequences(path: &str) -> Vec<String> {
    Vec::new()
}

fn mult_seq_alignment(input: &[String]) {
    println!("Hello, world!");
}

fn main() {
    let input = get_sequences("input/MSA_16507.txt");
    mult_seq_alignment(&input);
}
<commit_msg>All changes were committed<commit_after>fn get_sequences(path: &str) -> Vec<String> {
    vec!["PPGVKSDCAS".to_string(),
         "PADGVKDCAS".to_string(),
         "PPDGKSDS".to_string(),
         "GADGKDCCS".to_string(),
         "GADGKDCAS".to_string()]
    // Vec::new()
}

fn mult_seq_alignment(input: &[String]) {
    println!("Hello, world!");
}

fn main() {
    let input = get_sequences("input/MSA_16507.txt");
    mult_seq_alignment(&input);
}
<|endoftext|>


<commit_before>use anyhow::Result;
use bitflags::bitflags;
use thiserror::Error;

use crate::{
    aspace::{AbsoluteAddressSpace, AddressSpace},
    RVA, VA,
};

#[derive(Error, Debug)]
pub enum ModuleError {
    #[error("invalid address: {0:#x}")]
    InvalidAddress(u64),
}

#[derive(Copy, Clone, Debug)]
pub enum Arch {
    X32,
    X64,
}

impl Arch {
    pub fn pointer_size(&self) -> usize {
        match self {
            Arch::X32 => 4,
            Arch::X64 => 8,
        }
    }
}

bitflags! {
    pub struct Permissions: u8 {
        const R = 0b0000_0001;
        const W = 0b0000_0010;
        const X = 0b0000_0100;
        const RW = Self::R.bits | Self::W.bits;
        const RX =  Self::R.bits | Self::X.bits;
        const WX =  Self::W.bits | Self::X.bits;
        const RWX =  Self::R.bits | Self::W.bits | Self::X.bits;
    }
}

#[derive(Debug, Clone)]
pub struct Section {
    // source data, from the PE file, relative to file start.
    pub physical_range: std::ops::Range<RVA>,
    // as mapped into memory with absolute addresses.
    pub virtual_range:  std::ops::Range<VA>,
    pub perms:          Permissions,
    pub name:           String,
}

/// An address space, as a file would be loaded into memory.
/// This has an associated architecture (e.g. x32 or x64),
/// base address, and collection of sections.
/// This is the information that we'd expect to be common across formats.
#[derive(Clone)]
pub struct Module {
    pub arch:          Arch,
    pub sections:      Vec<Section>,
    pub address_space: AbsoluteAddressSpace,
}

impl Module {
    pub fn read_va_at_rva(&self, offset: RVA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_rva(&self, offset: RVA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as RVA),
        }
    }

    pub fn read_va_at_va(&self, offset: VA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_va(&self, offset: VA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as RVA),
        }
    }

    pub fn probe_va(&self, offset: VA, perm: Permissions) -> bool {
        self.sections
            .iter()
            .any(|section| section.virtual_range.contains(&offset) && section.perms.intersects(perm))
    }

    pub fn probe_rva(&self, offset: RVA, perm: Permissions) -> bool {
        let va = self.address_space.base_address + offset;
        self.probe_va(va, perm)
    }
}
<commit_msg>module: add `file_offset(va)` accessor<commit_after>use anyhow::Result;
use bitflags::bitflags;
use thiserror::Error;

use crate::{
    aspace::{AbsoluteAddressSpace, AddressSpace},
    pagemap::PageMapError::NotMapped,
    RVA, VA,
};

#[derive(Error, Debug)]
pub enum ModuleError {
    #[error("invalid address: {0:#x}")]
    InvalidAddress(u64),
}

#[derive(Copy, Clone, Debug)]
pub enum Arch {
    X32,
    X64,
}

impl Arch {
    pub fn pointer_size(&self) -> usize {
        match self {
            Arch::X32 => 4,
            Arch::X64 => 8,
        }
    }
}

bitflags! {
    pub struct Permissions: u8 {
        const R = 0b0000_0001;
        const W = 0b0000_0010;
        const X = 0b0000_0100;
        const RW = Self::R.bits | Self::W.bits;
        const RX =  Self::R.bits | Self::X.bits;
        const WX =  Self::W.bits | Self::X.bits;
        const RWX =  Self::R.bits | Self::W.bits | Self::X.bits;
    }
}

#[derive(Debug, Clone)]
pub struct Section {
    // source data, from the PE file, relative to file start.
    pub physical_range: std::ops::Range<RVA>,
    // as mapped into memory with absolute addresses.
    pub virtual_range:  std::ops::Range<VA>,
    pub perms:          Permissions,
    pub name:           String,
}

/// An address space, as a file would be loaded into memory.
/// This has an associated architecture (e.g. x32 or x64),
/// base address, and collection of sections.
/// This is the information that we'd expect to be common across formats.
#[derive(Clone)]
pub struct Module {
    pub arch:          Arch,
    pub sections:      Vec<Section>,
    pub address_space: AbsoluteAddressSpace,
}

impl Module {
    pub fn read_va_at_rva(&self, offset: RVA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_rva(&self, offset: RVA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.relative.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.relative.read_u64(offset)? as RVA),
        }
    }

    pub fn read_va_at_va(&self, offset: VA) -> Result<VA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as VA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as VA),
        }
    }

    pub fn read_rva_at_va(&self, offset: VA) -> Result<RVA> {
        match self.arch {
            Arch::X32 => Ok(self.address_space.read_u32(offset)? as RVA),
            Arch::X64 => Ok(self.address_space.read_u64(offset)? as RVA),
        }
    }

    pub fn probe_va(&self, offset: VA, perm: Permissions) -> bool {
        self.sections
            .iter()
            .any(|section| section.virtual_range.contains(&offset) && section.perms.intersects(perm))
    }

    pub fn probe_rva(&self, offset: RVA, perm: Permissions) -> bool {
        let va = self.address_space.base_address + offset;
        self.probe_va(va, perm)
    }

    pub fn file_offset(&self, va: VA) -> Result<usize> {
        if let Some(sec) = self.sections.iter().find(|&sec| sec.virtual_range.contains(&va)) {
            let offset = va - sec.virtual_range.start;
            return Ok((offset + sec.physical_range.start) as usize);
        } else {
            return Err(NotMapped.into());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::EmptyRequest,
    types::{
        AccountBalanceRequest, AccountBalanceResponse, BlockRequest, BlockResponse,
        NetworkListResponse, NetworkOptionsResponse, NetworkRequest, NetworkStatusResponse,
    },
};
use aptos_rest_client::aptos_api_types::mime_types::JSON;
use reqwest::{header::CONTENT_TYPE, Client as ReqwestClient};
use url::Url;

pub struct RosettaClient {
    address: Url,
    inner: ReqwestClient,
}

impl RosettaClient {
    pub fn new(address: Url) -> RosettaClient {
        RosettaClient {
            address,
            inner: ReqwestClient::new(),
        }
    }

    pub async fn account_balance(
        &self,
        request: &AccountBalanceRequest,
    ) -> anyhow::Result<AccountBalanceResponse> {
        let response = self
            .inner
            .post(self.address.join("account/balance").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn block(&self, request: &BlockRequest) -> anyhow::Result<BlockResponse> {
        let response = self
            .inner
            .post(self.address.join("block").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_list(&self) -> anyhow::Result<NetworkListResponse> {
        let response = self
            .inner
            .post(self.address.join("network/list").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(&EmptyRequest)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_options(
        &self,
        request: &NetworkRequest,
    ) -> anyhow::Result<NetworkOptionsResponse> {
        let response = self
            .inner
            .post(self.address.join("network/options").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_status(
        &self,
        request: &NetworkRequest,
    ) -> anyhow::Result<NetworkStatusResponse> {
        let response = self
            .inner
            .post(self.address.join("network/status").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    async fn json<T: serde::de::DeserializeOwned>(
        &self,
        response: reqwest::Response,
    ) -> anyhow::Result<T> {
        if !response.status().is_success() {
            return Err(anyhow::anyhow!(
                "Request failed: {:?}",
                response.error_for_status()
            ));
        }

        Ok(response.json().await?)
    }
}
<commit_msg>[aptos-rosetta] More rosetta documentation<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::EmptyRequest,
    types::{
        AccountBalanceRequest, AccountBalanceResponse, BlockRequest, BlockResponse,
        NetworkListResponse, NetworkOptionsResponse, NetworkRequest, NetworkStatusResponse,
    },
};
use aptos_rest_client::aptos_api_types::mime_types::JSON;
use reqwest::{header::CONTENT_TYPE, Client as ReqwestClient};
use url::Url;

/// Client for testing & interacting with a Rosetta service
pub struct RosettaClient {
    address: Url,
    inner: ReqwestClient,
}

impl RosettaClient {
    pub fn new(address: Url) -> RosettaClient {
        RosettaClient {
            address,
            inner: ReqwestClient::new(),
        }
    }

    pub async fn account_balance(
        &self,
        request: &AccountBalanceRequest,
    ) -> anyhow::Result<AccountBalanceResponse> {
        let response = self
            .inner
            .post(self.address.join("account/balance").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn block(&self, request: &BlockRequest) -> anyhow::Result<BlockResponse> {
        let response = self
            .inner
            .post(self.address.join("block").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_list(&self) -> anyhow::Result<NetworkListResponse> {
        let response = self
            .inner
            .post(self.address.join("network/list").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(&EmptyRequest)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_options(
        &self,
        request: &NetworkRequest,
    ) -> anyhow::Result<NetworkOptionsResponse> {
        let response = self
            .inner
            .post(self.address.join("network/options").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    pub async fn network_status(
        &self,
        request: &NetworkRequest,
    ) -> anyhow::Result<NetworkStatusResponse> {
        let response = self
            .inner
            .post(self.address.join("network/status").unwrap())
            .header(CONTENT_TYPE, JSON)
            .body(serde_json::to_string(request)?)
            .send()
            .await?;

        self.json(response).await
    }

    async fn json<T: serde::de::DeserializeOwned>(
        &self,
        response: reqwest::Response,
    ) -> anyhow::Result<T> {
        if !response.status().is_success() {
            return Err(anyhow::anyhow!(
                "Request failed: {:?}",
                response.error_for_status()
            ));
        }

        Ok(response.json().await?)
    }
}
<|endoftext|>


<commit_before>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use std::{ffi::OsString, path::PathBuf};

use flycheck::FlycheckConfig;
use lsp_types::ClientCapabilities;
use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
use serde::Deserialize;
use vfs::AbsPathBuf;

use crate::diagnostics::DiagnosticsConfig;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub publish_diagnostics: bool,
    pub diagnostics: DiagnosticsConfig,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo_autoreload: bool,
    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub flycheck: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub assist: AssistConfig,
    pub call_info_full: bool,
    pub lens: LensConfig,
    pub hover: HoverConfig,

    pub with_sysroot: bool,
    pub linked_projects: Vec<LinkedProject>,
    pub root_path: AbsPathBuf,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum LinkedProject {
    ProjectManifest(ProjectManifest),
    InlineJsonProject(ProjectJson),
}

impl From<ProjectManifest> for LinkedProject {
    fn from(v: ProjectManifest) -> Self {
        LinkedProject::ProjectManifest(v)
    }
}

impl From<ProjectJson> for LinkedProject {
    fn from(v: ProjectJson) -> Self {
        LinkedProject::InlineJsonProject(v)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LensConfig {
    pub run: bool,
    pub debug: bool,
    pub implementations: bool,
}

impl Default for LensConfig {
    fn default() -> Self {
        Self { run: true, debug: true, implementations: true }
    }
}

impl LensConfig {
    pub const NO_LENS: LensConfig = Self { run: false, debug: false, implementations: false };

    pub fn any(&self) -> bool {
        self.implementations || self.runnable()
    }

    pub fn none(&self) -> bool {
        !self.any()
    }

    pub fn runnable(&self) -> bool {
        self.run || self.debug
    }
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt { extra_args: Vec<String> },
    CustomCommand { command: String, args: Vec<String> },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
    pub hierarchical_symbols: bool,
    pub code_action_literals: bool,
    pub work_done_progress: bool,
    pub code_action_group: bool,
    pub resolve_code_action: bool,
    pub hover_actions: bool,
    pub status_notification: bool,
    pub signature_help_label_offsets: bool,
}

impl Config {
    pub fn new(root_path: AbsPathBuf) -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            diagnostics: DiagnosticsConfig::default(),
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig { cargo_toml_not_found: true },

            cargo_autoreload: true,
            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            flycheck: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                all_features: false,
                extra_args: Vec::new(),
                features: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
                ..CompletionConfig::default()
            },
            assist: AssistConfig::default(),
            call_info_full: true,
            lens: LensConfig::default(),
            hover: HoverConfig::default(),
            linked_projects: Vec::new(),
            root_path,
        }
    }

    pub fn update(&mut self, json: serde_json::Value) {
        log::info!("Config::update({:#})", json);

        if json.is_null() {
            return;
        }

        let data = ConfigData::from_json(json);

        self.with_sysroot = data.withSysroot;
        self.publish_diagnostics = data.diagnostics_enable;
        self.diagnostics = DiagnosticsConfig {
            warnings_as_info: data.diagnostics_warningsAsInfo,
            warnings_as_hint: data.diagnostics_warningsAsHint,
        };
        self.lru_capacity = data.lruCapacity;
        self.files.watcher = match data.files_watcher.as_str() {
            "notify" => FilesWatcher::Notify,
            "client" | _ => FilesWatcher::Client,
        };
        self.notifications =
            NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound };
        self.cargo_autoreload = data.cargo_autoreload;
        self.cargo = CargoConfig {
            no_default_features: data.cargo_noDefaultFeatures,
            all_features: data.cargo_allFeatures,
            features: data.cargo_features.clone(),
            load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck,
            target: data.cargo_target,
        };

        self.proc_macro_srv = if data.procMacro_enable {
            std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()]))
        } else {
            None
        };

        self.rustfmt = match data.rustfmt_overrideCommand {
            Some(mut args) if !args.is_empty() => {
                let command = args.remove(0);
                RustfmtConfig::CustomCommand { command, args }
            }
            Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs },
        };

        self.flycheck = if data.checkOnSave_enable {
            let flycheck_config = match data.checkOnSave_overrideCommand {
                Some(mut args) if !args.is_empty() => {
                    let command = args.remove(0);
                    FlycheckConfig::CustomCommand { command, args }
                }
                Some(_) | None => FlycheckConfig::CargoCommand {
                    command: data.checkOnSave_command,
                    all_targets: data.checkOnSave_allTargets,
                    all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures),
                    features: data.checkOnSave_features.unwrap_or(data.cargo_features),
                    extra_args: data.checkOnSave_extraArgs,
                },
            };
            Some(flycheck_config)
        } else {
            None
        };

        self.inlay_hints = InlayHintsConfig {
            type_hints: data.inlayHints_typeHints,
            parameter_hints: data.inlayHints_parameterHints,
            chaining_hints: data.inlayHints_chainingHints,
            max_length: data.inlayHints_maxLength,
        };

        self.completion.enable_postfix_completions = data.completion_postfix_enable;
        self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
        self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;

        self.call_info_full = data.callInfo_full;

        self.lens = LensConfig {
            run: data.lens_enable && data.lens_run,
            debug: data.lens_enable && data.lens_debug,
            implementations: data.lens_enable && data.lens_implementations,
        };

        if !data.linkedProjects.is_empty() {
            self.linked_projects.clear();
            for linked_project in data.linkedProjects {
                let linked_project = match linked_project {
                    ManifestOrProjectJson::Manifest(it) => {
                        let path = self.root_path.join(it);
                        match ProjectManifest::from_manifest_file(path) {
                            Ok(it) => it.into(),
                            Err(_) => continue,
                        }
                    }
                    ManifestOrProjectJson::ProjectJson(it) => {
                        ProjectJson::new(&self.root_path, it).into()
                    }
                };
                self.linked_projects.push(linked_project);
            }
        }

        self.hover = HoverConfig {
            implementations: data.hoverActions_enable && data.hoverActions_implementations,
            run: data.hoverActions_enable && data.hoverActions_run,
            debug: data.hoverActions_enable && data.hoverActions_debug,
            goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef,
        };

        log::info!("Config::update() = {:#?}", self);
    }

    pub fn update_caps(&mut self, caps: &ClientCapabilities) {
        if let Some(doc_caps) = caps.text_document.as_ref() {
            if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) {
                self.client_caps.location_link = value;
            }
            if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only)
            {
                self.client_caps.line_folding_only = value
            }
            if let Some(value) = doc_caps
                .document_symbol
                .as_ref()
                .and_then(|it| it.hierarchical_document_symbol_support)
            {
                self.client_caps.hierarchical_symbols = value
            }
            if let Some(value) =
                doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some())
            {
                self.client_caps.code_action_literals = value;
            }
            if let Some(value) = doc_caps
                .signature_help
                .as_ref()
                .and_then(|it| it.signature_information.as_ref())
                .and_then(|it| it.parameter_information.as_ref())
                .and_then(|it| it.label_offset_support)
            {
                self.client_caps.signature_help_label_offsets = value;
            }

            self.completion.allow_snippets(false);
            if let Some(completion) = &doc_caps.completion {
                if let Some(completion_item) = &completion.completion_item {
                    if let Some(value) = completion_item.snippet_support {
                        self.completion.allow_snippets(value);
                    }
                }
            }
        }

        if let Some(window_caps) = caps.window.as_ref() {
            if let Some(value) = window_caps.work_done_progress {
                self.client_caps.work_done_progress = value;
            }
        }

        self.assist.allow_snippets(false);
        if let Some(experimental) = &caps.experimental {
            let get_bool =
                |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true);

            let snippet_text_edit = get_bool("snippetTextEdit");
            self.assist.allow_snippets(snippet_text_edit);

            self.client_caps.code_action_group = get_bool("codeActionGroup");
            self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
            self.client_caps.hover_actions = get_bool("hoverActions");
            self.client_caps.status_notification = get_bool("statusNotification");
        }
    }
}

#[derive(Deserialize)]
#[serde(untagged)]
enum ManifestOrProjectJson {
    Manifest(PathBuf),
    ProjectJson(ProjectJsonData),
}

macro_rules! config_data {
    (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => {
        #[allow(non_snake_case)]
        struct $name { $($field: $ty,)* }
        impl $name {
            fn from_json(mut json: serde_json::Value) -> $name {
                $name {$(
                    $field: {
                        let pointer = stringify!($field).replace('_', "/");
                        let pointer = format!("/{}", pointer);
                        json.pointer_mut(&pointer)
                            .and_then(|it| serde_json::from_value(it.take()).ok())
                            .unwrap_or($default)
                    },
                )*}
            }
        }

    };
}

config_data! {
    struct ConfigData {
        callInfo_full: bool = true,

        cargo_autoreload: bool           = true,
        cargo_allFeatures: bool          = false,
        cargo_features: Vec<String>      = Vec::new(),
        cargo_loadOutDirsFromCheck: bool = false,
        cargo_noDefaultFeatures: bool    = false,
        cargo_target: Option<String>     = None,

        checkOnSave_allFeatures: Option<bool>            = None,
        checkOnSave_allTargets: bool                     = true,
        checkOnSave_command: String                      = "check".into(),
        checkOnSave_enable: bool                         = false,
        checkOnSave_extraArgs: Vec<String>               = Vec::new(),
        checkOnSave_features: Option<Vec<String>>        = None,
        checkOnSave_overrideCommand: Option<Vec<String>> = None,

        completion_addCallArgumentSnippets: bool = true,
        completion_addCallParenthesis: bool      = true,
        completion_postfix_enable: bool          = true,

        diagnostics_enable: bool                = true,
        diagnostics_warningsAsHint: Vec<String> = Vec::new(),
        diagnostics_warningsAsInfo: Vec<String> = Vec::new(),

        files_watcher: String = "client".into(),

        hoverActions_debug: bool           = true,
        hoverActions_enable: bool          = true,
        hoverActions_gotoTypeDef: bool     = true,
        hoverActions_implementations: bool = true,
        hoverActions_run: bool             = true,

        inlayHints_chainingHints: bool      = true,
        inlayHints_maxLength: Option<usize> = None,
        inlayHints_parameterHints: bool     = true,
        inlayHints_typeHints: bool          = true,

        lens_debug: bool           = true,
        lens_enable: bool          = true,
        lens_implementations: bool = true,
        lens_run: bool             = true,

        linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(),
        lruCapacity: Option<usize>                 = None,
        notifications_cargoTomlNotFound: bool      = true,
        procMacro_enable: bool                     = false,

        rustfmt_extraArgs: Vec<String>               = Vec::new(),
        rustfmt_overrideCommand: Option<Vec<String>> = None,

        withSysroot: bool = true,
    }
}
<commit_msg>Protect against `{}`<commit_after>//! Config used by the language server.
//!
//! We currently get this config from `initialize` LSP request, which is not the
//! best way to do it, but was the simplest thing we could implement.
//!
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.

use std::{ffi::OsString, path::PathBuf};

use flycheck::FlycheckConfig;
use lsp_types::ClientCapabilities;
use ra_ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig};
use ra_project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
use serde::Deserialize;
use vfs::AbsPathBuf;

use crate::diagnostics::DiagnosticsConfig;

#[derive(Debug, Clone)]
pub struct Config {
    pub client_caps: ClientCapsConfig,

    pub publish_diagnostics: bool,
    pub diagnostics: DiagnosticsConfig,
    pub lru_capacity: Option<usize>,
    pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>,
    pub files: FilesConfig,
    pub notifications: NotificationsConfig,

    pub cargo_autoreload: bool,
    pub cargo: CargoConfig,
    pub rustfmt: RustfmtConfig,
    pub flycheck: Option<FlycheckConfig>,

    pub inlay_hints: InlayHintsConfig,
    pub completion: CompletionConfig,
    pub assist: AssistConfig,
    pub call_info_full: bool,
    pub lens: LensConfig,
    pub hover: HoverConfig,

    pub with_sysroot: bool,
    pub linked_projects: Vec<LinkedProject>,
    pub root_path: AbsPathBuf,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum LinkedProject {
    ProjectManifest(ProjectManifest),
    InlineJsonProject(ProjectJson),
}

impl From<ProjectManifest> for LinkedProject {
    fn from(v: ProjectManifest) -> Self {
        LinkedProject::ProjectManifest(v)
    }
}

impl From<ProjectJson> for LinkedProject {
    fn from(v: ProjectJson) -> Self {
        LinkedProject::InlineJsonProject(v)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LensConfig {
    pub run: bool,
    pub debug: bool,
    pub implementations: bool,
}

impl Default for LensConfig {
    fn default() -> Self {
        Self { run: true, debug: true, implementations: true }
    }
}

impl LensConfig {
    pub const NO_LENS: LensConfig = Self { run: false, debug: false, implementations: false };

    pub fn any(&self) -> bool {
        self.implementations || self.runnable()
    }

    pub fn none(&self) -> bool {
        !self.any()
    }

    pub fn runnable(&self) -> bool {
        self.run || self.debug
    }
}

#[derive(Debug, Clone)]
pub struct FilesConfig {
    pub watcher: FilesWatcher,
    pub exclude: Vec<String>,
}

#[derive(Debug, Clone)]
pub enum FilesWatcher {
    Client,
    Notify,
}

#[derive(Debug, Clone)]
pub struct NotificationsConfig {
    pub cargo_toml_not_found: bool,
}

#[derive(Debug, Clone)]
pub enum RustfmtConfig {
    Rustfmt { extra_args: Vec<String> },
    CustomCommand { command: String, args: Vec<String> },
}

#[derive(Debug, Clone, Default)]
pub struct ClientCapsConfig {
    pub location_link: bool,
    pub line_folding_only: bool,
    pub hierarchical_symbols: bool,
    pub code_action_literals: bool,
    pub work_done_progress: bool,
    pub code_action_group: bool,
    pub resolve_code_action: bool,
    pub hover_actions: bool,
    pub status_notification: bool,
    pub signature_help_label_offsets: bool,
}

impl Config {
    pub fn new(root_path: AbsPathBuf) -> Self {
        Config {
            client_caps: ClientCapsConfig::default(),

            with_sysroot: true,
            publish_diagnostics: true,
            diagnostics: DiagnosticsConfig::default(),
            lru_capacity: None,
            proc_macro_srv: None,
            files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() },
            notifications: NotificationsConfig { cargo_toml_not_found: true },

            cargo_autoreload: true,
            cargo: CargoConfig::default(),
            rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() },
            flycheck: Some(FlycheckConfig::CargoCommand {
                command: "check".to_string(),
                all_targets: true,
                all_features: false,
                extra_args: Vec::new(),
                features: Vec::new(),
            }),

            inlay_hints: InlayHintsConfig {
                type_hints: true,
                parameter_hints: true,
                chaining_hints: true,
                max_length: None,
            },
            completion: CompletionConfig {
                enable_postfix_completions: true,
                add_call_parenthesis: true,
                add_call_argument_snippets: true,
                ..CompletionConfig::default()
            },
            assist: AssistConfig::default(),
            call_info_full: true,
            lens: LensConfig::default(),
            hover: HoverConfig::default(),
            linked_projects: Vec::new(),
            root_path,
        }
    }

    pub fn update(&mut self, json: serde_json::Value) {
        log::info!("Config::update({:#})", json);

        if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) {
            return;
        }

        let data = ConfigData::from_json(json);

        self.with_sysroot = data.withSysroot;
        self.publish_diagnostics = data.diagnostics_enable;
        self.diagnostics = DiagnosticsConfig {
            warnings_as_info: data.diagnostics_warningsAsInfo,
            warnings_as_hint: data.diagnostics_warningsAsHint,
        };
        self.lru_capacity = data.lruCapacity;
        self.files.watcher = match data.files_watcher.as_str() {
            "notify" => FilesWatcher::Notify,
            "client" | _ => FilesWatcher::Client,
        };
        self.notifications =
            NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound };
        self.cargo_autoreload = data.cargo_autoreload;
        self.cargo = CargoConfig {
            no_default_features: data.cargo_noDefaultFeatures,
            all_features: data.cargo_allFeatures,
            features: data.cargo_features.clone(),
            load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck,
            target: data.cargo_target,
        };

        self.proc_macro_srv = if data.procMacro_enable {
            std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()]))
        } else {
            None
        };

        self.rustfmt = match data.rustfmt_overrideCommand {
            Some(mut args) if !args.is_empty() => {
                let command = args.remove(0);
                RustfmtConfig::CustomCommand { command, args }
            }
            Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs },
        };

        self.flycheck = if data.checkOnSave_enable {
            let flycheck_config = match data.checkOnSave_overrideCommand {
                Some(mut args) if !args.is_empty() => {
                    let command = args.remove(0);
                    FlycheckConfig::CustomCommand { command, args }
                }
                Some(_) | None => FlycheckConfig::CargoCommand {
                    command: data.checkOnSave_command,
                    all_targets: data.checkOnSave_allTargets,
                    all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures),
                    features: data.checkOnSave_features.unwrap_or(data.cargo_features),
                    extra_args: data.checkOnSave_extraArgs,
                },
            };
            Some(flycheck_config)
        } else {
            None
        };

        self.inlay_hints = InlayHintsConfig {
            type_hints: data.inlayHints_typeHints,
            parameter_hints: data.inlayHints_parameterHints,
            chaining_hints: data.inlayHints_chainingHints,
            max_length: data.inlayHints_maxLength,
        };

        self.completion.enable_postfix_completions = data.completion_postfix_enable;
        self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
        self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;

        self.call_info_full = data.callInfo_full;

        self.lens = LensConfig {
            run: data.lens_enable && data.lens_run,
            debug: data.lens_enable && data.lens_debug,
            implementations: data.lens_enable && data.lens_implementations,
        };

        if !data.linkedProjects.is_empty() {
            self.linked_projects.clear();
            for linked_project in data.linkedProjects {
                let linked_project = match linked_project {
                    ManifestOrProjectJson::Manifest(it) => {
                        let path = self.root_path.join(it);
                        match ProjectManifest::from_manifest_file(path) {
                            Ok(it) => it.into(),
                            Err(_) => continue,
                        }
                    }
                    ManifestOrProjectJson::ProjectJson(it) => {
                        ProjectJson::new(&self.root_path, it).into()
                    }
                };
                self.linked_projects.push(linked_project);
            }
        }

        self.hover = HoverConfig {
            implementations: data.hoverActions_enable && data.hoverActions_implementations,
            run: data.hoverActions_enable && data.hoverActions_run,
            debug: data.hoverActions_enable && data.hoverActions_debug,
            goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef,
        };

        log::info!("Config::update() = {:#?}", self);
    }

    pub fn update_caps(&mut self, caps: &ClientCapabilities) {
        if let Some(doc_caps) = caps.text_document.as_ref() {
            if let Some(value) = doc_caps.definition.as_ref().and_then(|it| it.link_support) {
                self.client_caps.location_link = value;
            }
            if let Some(value) = doc_caps.folding_range.as_ref().and_then(|it| it.line_folding_only)
            {
                self.client_caps.line_folding_only = value
            }
            if let Some(value) = doc_caps
                .document_symbol
                .as_ref()
                .and_then(|it| it.hierarchical_document_symbol_support)
            {
                self.client_caps.hierarchical_symbols = value
            }
            if let Some(value) =
                doc_caps.code_action.as_ref().map(|it| it.code_action_literal_support.is_some())
            {
                self.client_caps.code_action_literals = value;
            }
            if let Some(value) = doc_caps
                .signature_help
                .as_ref()
                .and_then(|it| it.signature_information.as_ref())
                .and_then(|it| it.parameter_information.as_ref())
                .and_then(|it| it.label_offset_support)
            {
                self.client_caps.signature_help_label_offsets = value;
            }

            self.completion.allow_snippets(false);
            if let Some(completion) = &doc_caps.completion {
                if let Some(completion_item) = &completion.completion_item {
                    if let Some(value) = completion_item.snippet_support {
                        self.completion.allow_snippets(value);
                    }
                }
            }
        }

        if let Some(window_caps) = caps.window.as_ref() {
            if let Some(value) = window_caps.work_done_progress {
                self.client_caps.work_done_progress = value;
            }
        }

        self.assist.allow_snippets(false);
        if let Some(experimental) = &caps.experimental {
            let get_bool =
                |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true);

            let snippet_text_edit = get_bool("snippetTextEdit");
            self.assist.allow_snippets(snippet_text_edit);

            self.client_caps.code_action_group = get_bool("codeActionGroup");
            self.client_caps.resolve_code_action = get_bool("resolveCodeAction");
            self.client_caps.hover_actions = get_bool("hoverActions");
            self.client_caps.status_notification = get_bool("statusNotification");
        }
    }
}

#[derive(Deserialize)]
#[serde(untagged)]
enum ManifestOrProjectJson {
    Manifest(PathBuf),
    ProjectJson(ProjectJsonData),
}

macro_rules! config_data {
    (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => {
        #[allow(non_snake_case)]
        struct $name { $($field: $ty,)* }
        impl $name {
            fn from_json(mut json: serde_json::Value) -> $name {
                $name {$(
                    $field: {
                        let pointer = stringify!($field).replace('_', "/");
                        let pointer = format!("/{}", pointer);
                        json.pointer_mut(&pointer)
                            .and_then(|it| serde_json::from_value(it.take()).ok())
                            .unwrap_or($default)
                    },
                )*}
            }
        }

    };
}

config_data! {
    struct ConfigData {
        callInfo_full: bool = true,

        cargo_autoreload: bool           = true,
        cargo_allFeatures: bool          = false,
        cargo_features: Vec<String>      = Vec::new(),
        cargo_loadOutDirsFromCheck: bool = false,
        cargo_noDefaultFeatures: bool    = false,
        cargo_target: Option<String>     = None,

        checkOnSave_allFeatures: Option<bool>            = None,
        checkOnSave_allTargets: bool                     = true,
        checkOnSave_command: String                      = "check".into(),
        checkOnSave_enable: bool                         = false,
        checkOnSave_extraArgs: Vec<String>               = Vec::new(),
        checkOnSave_features: Option<Vec<String>>        = None,
        checkOnSave_overrideCommand: Option<Vec<String>> = None,

        completion_addCallArgumentSnippets: bool = true,
        completion_addCallParenthesis: bool      = true,
        completion_postfix_enable: bool          = true,

        diagnostics_enable: bool                = true,
        diagnostics_warningsAsHint: Vec<String> = Vec::new(),
        diagnostics_warningsAsInfo: Vec<String> = Vec::new(),

        files_watcher: String = "client".into(),

        hoverActions_debug: bool           = true,
        hoverActions_enable: bool          = true,
        hoverActions_gotoTypeDef: bool     = true,
        hoverActions_implementations: bool = true,
        hoverActions_run: bool             = true,

        inlayHints_chainingHints: bool      = true,
        inlayHints_maxLength: Option<usize> = None,
        inlayHints_parameterHints: bool     = true,
        inlayHints_typeHints: bool          = true,

        lens_debug: bool           = true,
        lens_enable: bool          = true,
        lens_implementations: bool = true,
        lens_run: bool             = true,

        linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(),
        lruCapacity: Option<usize>                 = None,
        notifications_cargoTomlNotFound: bool      = true,
        procMacro_enable: bool                     = false,

        rustfmt_extraArgs: Vec<String>               = Vec::new(),
        rustfmt_overrideCommand: Option<Vec<String>> = None,

        withSysroot: bool = true,
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;

use ::expr::{Expr, Type, Kint, Kfloat, Result, Error as E};
use ::env::{Env};
use ::util::*;
use ::eval::funcall;

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        pub fn $name(mut env: &mut Env, args: &Expr) -> Result<Expr> {
            let (init, args) = match args {
                &Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl),
                    _ => ($init, args)
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (&Expr::Int(x), &Expr::Int(y)) => Ok(kint(expr!(x $op y))),
                (&Expr::Float(x), &Expr::Int(y)) => Ok(kfloat(expr!(x $op (y as Kfloat)))),
                (&Expr::Int(x), &Expr::Float(y)) => Ok(kfloat(expr!((x as Kfloat) $op y))),
                (&Expr::Float(x), &Expr::Float(y)) => Ok(kfloat(expr!(x $op y))),
                (&Expr::Int(_), y) => Err(E::Type(Type::Int, y.clone())),
                (x, _) => Err(E::Type(Type::Int, x.clone())),
            }, &init, args)

        }
    }
}

def_arith_op!(k_add, +, kint(0));
def_arith_op!(k_sub, -, kint(0));
def_arith_op!(k_mul, *, kint(1));
def_arith_op!(k_div, /, kint(1));

pub fn k_concat(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let res = f_foldl(env, &|_, acc, x| match (acc, x) {
        (&Expr::Str(ref acc), &Expr::Str(ref x)) => Ok(kstr(format!("{}{}",acc, x))),
        (_, y) => Err(E::Type(Type::Str, y.clone()))
    }
                      , &kstr(""), &args);
    Ok(try!(res).clone())
}

pub fn k_funcall(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref f, ref args) => match f.deref() {
            &Expr::Proc(ref f) => funcall(env, f , args.deref()),
            f => Err(E::NotFunction(f.clone()))
        },
        args => Err(E::Form(args.clone()))
    }
}

pub fn k_cons(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (car, Any) (cdr, Any));
    Ok(kcons(car.clone(), cdr.clone()))
}

pub fn k_car(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((car, _), Cons));
    Ok(car.clone())
}

pub fn k_cdr(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((_, cdr), Cons));
    Ok(cdr.clone())

}

pub fn k_list(_: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(args.clone())
}

pub fn k_equal_p(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (x, Any) (y, Any));
    if x == y {
        // TODO: return `t`
        Ok(kint(1))
    } else {
        Ok(knil())
    }
}

pub fn k_string_to_number(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str));
    match s.parse() {
        // TODO: handle float case
        Ok(i) => Ok(Expr::Int(i)),
        Err(_) => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn k_substring(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str) &optional (start, Int) (end, Int));
    let len = s.len();
    let ilen = len as Kint;
    let start = start.unwrap_or(0);
    let end = end.unwrap_or(ilen);
    if 0 <= start && start <= end && end < ilen {
        let start = start as usize;
        let end = end as usize;
        Ok(kstr((&s[start..end]).to_owned()))
    } else {
        Err(E::InvalidArgument(args.clone()))
    }
}

pub fn init(mut env: &mut Env) -> Result<()>{
    env.fregister("+",       kprim("k_add", k_add));
    env.fregister("-",       kprim("k_sub", k_sub));
    env.fregister("/",       kprim("k_div", k_div));
    env.fregister("*",       kprim("k_mul", k_mul));
    env.fregister("concat",  kprim("k_concat", k_concat));
    env.fregister("funcall", kprim("k_funcall", k_funcall));
    env.fregister("cons",    kprim("k_cons", k_cons));
    env.fregister("car",     kprim("k_car", k_car));
    env.fregister("cdr",     kprim("k_cdr", k_cdr));
    env.fregister("list",    kprim("k_list",k_list));
    env.fregister("equal?",  kprim("k_equal_p", k_equal_p));
    env.fregister("string-to-number", kprim("k_string_to_number", k_string_to_number));
    env.fregister("substring", kprim("k_substring", k_substring));
    env.register("t", ksym("t"));
    Ok(())
}

<commit_msg>return t<commit_after>use std::ops::Deref;

use ::expr::{Expr, Type, Kint, Kfloat, Result, Error as E};
use ::env::{Env};
use ::util::*;
use ::eval::funcall;

// since rust's macro cannot treat binop, work around macro is needed.
macro_rules! expr {
    ($e:expr) => {
        $e
    }
}

macro_rules! def_arith_op {
    ($name: ident, $op: tt, $init: expr) => {
        pub fn $name(mut env: &mut Env, args: &Expr) -> Result<Expr> {
            let (init, args) = match args {
                &Expr::Cons(ref hd, ref tl) => match tl.deref() {
                    tl @ &Expr::Cons(_, _) => (hd.deref().clone(), tl),
                    _ => ($init, args)
                },
                args => ($init, args)
            };
            f_foldl(env, &|_, x, y| match (x, y) {
                (&Expr::Int(x), &Expr::Int(y)) => Ok(kint(expr!(x $op y))),
                (&Expr::Float(x), &Expr::Int(y)) => Ok(kfloat(expr!(x $op (y as Kfloat)))),
                (&Expr::Int(x), &Expr::Float(y)) => Ok(kfloat(expr!((x as Kfloat) $op y))),
                (&Expr::Float(x), &Expr::Float(y)) => Ok(kfloat(expr!(x $op y))),
                (&Expr::Int(_), y) => Err(E::Type(Type::Int, y.clone())),
                (x, _) => Err(E::Type(Type::Int, x.clone())),
            }, &init, args)

        }
    }
}

def_arith_op!(k_add, +, kint(0));
def_arith_op!(k_sub, -, kint(0));
def_arith_op!(k_mul, *, kint(1));
def_arith_op!(k_div, /, kint(1));

pub fn k_concat(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    let res = f_foldl(env, &|_, acc, x| match (acc, x) {
        (&Expr::Str(ref acc), &Expr::Str(ref x)) => Ok(kstr(format!("{}{}",acc, x))),
        (_, y) => Err(E::Type(Type::Str, y.clone()))
    }
                      , &kstr(""), &args);
    Ok(try!(res).clone())
}

pub fn k_funcall(mut env: &mut Env, args: &Expr) -> Result<Expr> {
    match args {
        &Expr::Cons(ref f, ref args) => match f.deref() {
            &Expr::Proc(ref f) => funcall(env, f , args.deref()),
            f => Err(E::NotFunction(f.clone()))
        },
        args => Err(E::Form(args.clone()))
    }
}

pub fn k_cons(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (car, Any) (cdr, Any));
    Ok(kcons(car.clone(), cdr.clone()))
}

pub fn k_car(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((car, _), Cons));
    Ok(car.clone())
}

pub fn k_cdr(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, ((_, cdr), Cons));
    Ok(cdr.clone())

}

pub fn k_list(_: &mut Env, args: &Expr) -> Result<Expr> {
    Ok(args.clone())
}

pub fn k_equal_p(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (x, Any) (y, Any));
    if x == y {
        Ok(ksym("t"))
    } else {
        Ok(knil())
    }
}

pub fn k_string_to_number(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str));
    match s.parse() {
        // TODO: handle float case
        Ok(i) => Ok(Expr::Int(i)),
        Err(_) => Err(E::InvalidArgument(args.clone()))
    }
}

pub fn k_substring(_: &mut Env, args: &Expr) -> Result<Expr> {
    get_args!(args, (s, Str) &optional (start, Int) (end, Int));
    let len = s.len();
    let ilen = len as Kint;
    let start = start.unwrap_or(0);
    let end = end.unwrap_or(ilen);
    if 0 <= start && start <= end && end < ilen {
        let start = start as usize;
        let end = end as usize;
        Ok(kstr((&s[start..end]).to_owned()))
    } else {
        Err(E::InvalidArgument(args.clone()))
    }
}

pub fn init(mut env: &mut Env) -> Result<()>{
    env.fregister("+",       kprim("k_add", k_add));
    env.fregister("-",       kprim("k_sub", k_sub));
    env.fregister("/",       kprim("k_div", k_div));
    env.fregister("*",       kprim("k_mul", k_mul));
    env.fregister("concat",  kprim("k_concat", k_concat));
    env.fregister("funcall", kprim("k_funcall", k_funcall));
    env.fregister("cons",    kprim("k_cons", k_cons));
    env.fregister("car",     kprim("k_car", k_car));
    env.fregister("cdr",     kprim("k_cdr", k_cdr));
    env.fregister("list",    kprim("k_list",k_list));
    env.fregister("equal?",  kprim("k_equal_p", k_equal_p));
    env.fregister("string-to-number", kprim("k_string_to_number", k_string_to_number));
    env.fregister("substring", kprim("k_substring", k_substring));
    env.register("t", ksym("t"));
    Ok(())
}

<|endoftext|>


<commit_before>// Contributing
//
// New example code:
// - Please update the corresponding section in the derive tutorial
// - Building: They must be added to `Cargo.toml` with the appropriate `required-features`.
// - Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax
//
// See also the general CONTRIBUTING

//! # Documentation: Derive Tutorial
//!
//! 1. [Quick Start](#quick-start)
//! 2. [Configuring the Parser](#configuring-the-parser)
//! 3. [Adding Arguments](#adding-arguments)
//!     1. [Positionals](#positionals)
//!     2. [Options](#options)
//!     3. [Flags](#flags)
//!     4. [Subcommands](#subcommands)
//!     5. [Defaults](#defaults)
//! 4. Validation
//!     1. [Enumerated values](#enumerated-values)
//!     2. [Validated values](#validated-values)
//!     3. [Argument Relations](#argument-relations)
//!     4. [Custom Validation](#custom-validation)
//! 5. [Testing](#testing)
//!
//! See also
//! - [FAQ: When should I use the builder vs derive APIs?][crate::_faq#when-should-i-use-the-builder-vs-derive-apis]
//! - The [cookbook][crate::_cookbook] for more application-focused examples
//!
//! ## Quick Start
//!
//! You can create an application declaratively with a `struct` and some
//! attributes.  **This requires enabling the [`derive` feature flag][crate::_features].**
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/01_quick.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/01_quick.md")]
//!
//! ## Configuring the Parser
//!
//! You use derive [`Parser`][crate::Parser] to start building a parser.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_apps.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/02_apps.md")]
//!
//! You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_crate.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/02_crate.md")]
//!
//! You can use attributes to change the application level behavior of clap.  Any [`Command`][crate::Command]] builder function can be used as an attribute.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.md")]
//!
//! ## Adding Arguments
//!
//! ### Positionals
//!
//! You can have users specify values by their position on the command-line:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.md")]
//!
//! ### Options
//!
//! You can name your arguments with a flag:
//! - Order doesn't matter
//! - They can be optional
//! - Intent is clearer
//!
//! The `#[clap(short = 'n')]` and `#[clap(long = "name")]` attributes that define
//! the flags are [`Arg`][crate::Args] methods that are derived from the field name when no value
//! is specified (`#[clap(short)]` and `#[clap(long)]`).
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_02_option.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_02_option.md")]
//!
//! ### Flags
//!
//! Flags can also be switches that can be on/off.  This is enabled via the
//! `#[clap(action = ArgAction::SetTrue)]` attribute though this is implied when the field is a
//! `bool`.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.md")]
//!
//! Or counted with `#[clap(action = clap::ArgAction::Count)]`:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.md")]
//!
//! ### Subcommands
//!
//! Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each
//! instance of a [Subcommand][crate::Subcommand] can have its own version, author(s), Args, and even its own
//! subcommands.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.rs")]
//! ```
//! We used a struct-variant to define the `add` subcommand.
//! Alternatively, you can use a struct for your subcommand's arguments:
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands_alt.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.md")]
//!
//! ### Defaults
//!
//! We've previously showed that arguments can be [`required`][crate::Arg::required] or optional.
//! When optional, you work with a `Option` and can `unwrap_or`.  Alternatively, you can
//! set `#[clap(default_value_t)]`.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.md")]
//!
//! ## Validation
//!
//! ### Enumerated values
//!
//! If you have arguments of specific values you want to test for, you can derive
//! [`ValueEnum`][crate::ValueEnum].
//!
//! This allows you specify the valid values for that argument. If the user does not use one of
//! those specific values, they will receive a graceful exit with error message informing them
//! of the mistake, and what the possible valid values are
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.md")]
//!
//! ### Validated values
//!
//! More generally, you can validate and parse into any data type.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.md")]
//!
//! A custom parser can be used to improve the error messages or provide additional validation:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.md")]
//!
//! ### Argument Relations
//!
//! You can declare dependencies or conflicts between [`Arg`][crate::Arg]s or even
//! [`ArgGroup`][crate::ArgGroup]s.
//!
//! [`ArgGroup`][crate::ArgGroup]s  make it easier to declare relations instead of having to list
//! each individually, or when you want a rule to apply "any but not all" arguments.
//!
//! Perhaps the most common use of [`ArgGroup`][crate::ArgGroup]s is to require one and *only* one
//! argument to be present out of a given set. Imagine that you had multiple arguments, and you
//! want one of them to be required, but making all of them required isn't feasible because perhaps
//! they conflict with each other.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.md")]
//!
//! ### Custom Validation
//!
//! As a last resort, you can create custom errors with the basics of clap's formatting.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.md")]
//!
//! ## Testing
//!
//! clap reports most development errors as `debug_assert!`s.  Rather than checking every
//! subcommand, you should have a test that calls
//! [`Command::debug_assert`][crate::Command::debug_assert]:
//! ```rust,no_run
#![doc = include_str!("../../examples/tutorial_derive/05_01_assert.rs")]
//! ```
<commit_msg>docs: remove extra bracket typo<commit_after>// Contributing
//
// New example code:
// - Please update the corresponding section in the derive tutorial
// - Building: They must be added to `Cargo.toml` with the appropriate `required-features`.
// - Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax
//
// See also the general CONTRIBUTING

//! # Documentation: Derive Tutorial
//!
//! 1. [Quick Start](#quick-start)
//! 2. [Configuring the Parser](#configuring-the-parser)
//! 3. [Adding Arguments](#adding-arguments)
//!     1. [Positionals](#positionals)
//!     2. [Options](#options)
//!     3. [Flags](#flags)
//!     4. [Subcommands](#subcommands)
//!     5. [Defaults](#defaults)
//! 4. Validation
//!     1. [Enumerated values](#enumerated-values)
//!     2. [Validated values](#validated-values)
//!     3. [Argument Relations](#argument-relations)
//!     4. [Custom Validation](#custom-validation)
//! 5. [Testing](#testing)
//!
//! See also
//! - [FAQ: When should I use the builder vs derive APIs?][crate::_faq#when-should-i-use-the-builder-vs-derive-apis]
//! - The [cookbook][crate::_cookbook] for more application-focused examples
//!
//! ## Quick Start
//!
//! You can create an application declaratively with a `struct` and some
//! attributes.  **This requires enabling the [`derive` feature flag][crate::_features].**
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/01_quick.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/01_quick.md")]
//!
//! ## Configuring the Parser
//!
//! You use derive [`Parser`][crate::Parser] to start building a parser.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_apps.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/02_apps.md")]
//!
//! You can use `#[clap(author, version, about)]` attribute defaults to fill these fields in from your `Cargo.toml` file.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_crate.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/02_crate.md")]
//!
//! You can use attributes to change the application level behavior of clap.  Any [`Command`][crate::Command] builder function can be used as an attribute.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/02_app_settings.md")]
//!
//! ## Adding Arguments
//!
//! ### Positionals
//!
//! You can have users specify values by their position on the command-line:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_03_positional.md")]
//!
//! ### Options
//!
//! You can name your arguments with a flag:
//! - Order doesn't matter
//! - They can be optional
//! - Intent is clearer
//!
//! The `#[clap(short = 'n')]` and `#[clap(long = "name")]` attributes that define
//! the flags are [`Arg`][crate::Args] methods that are derived from the field name when no value
//! is specified (`#[clap(short)]` and `#[clap(long)]`).
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_02_option.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_02_option.md")]
//!
//! ### Flags
//!
//! Flags can also be switches that can be on/off.  This is enabled via the
//! `#[clap(action = ArgAction::SetTrue)]` attribute though this is implied when the field is a
//! `bool`.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_bool.md")]
//!
//! Or counted with `#[clap(action = clap::ArgAction::Count)]`:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_01_flag_count.md")]
//!
//! ### Subcommands
//!
//! Subcommands are derived with `#[derive(Subcommand)]` and be added via `#[clap(subcommand)]` attribute. Each
//! instance of a [Subcommand][crate::Subcommand] can have its own version, author(s), Args, and even its own
//! subcommands.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.rs")]
//! ```
//! We used a struct-variant to define the `add` subcommand.
//! Alternatively, you can use a struct for your subcommand's arguments:
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands_alt.rs")]
//! ```
//!
#![doc = include_str!("../../examples/tutorial_derive/03_04_subcommands.md")]
//!
//! ### Defaults
//!
//! We've previously showed that arguments can be [`required`][crate::Arg::required] or optional.
//! When optional, you work with a `Option` and can `unwrap_or`.  Alternatively, you can
//! set `#[clap(default_value_t)]`.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/03_05_default_values.md")]
//!
//! ## Validation
//!
//! ### Enumerated values
//!
//! If you have arguments of specific values you want to test for, you can derive
//! [`ValueEnum`][crate::ValueEnum].
//!
//! This allows you specify the valid values for that argument. If the user does not use one of
//! those specific values, they will receive a graceful exit with error message informing them
//! of the mistake, and what the possible valid values are
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_01_enum.md")]
//!
//! ### Validated values
//!
//! More generally, you can validate and parse into any data type.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_02_parse.md")]
//!
//! A custom parser can be used to improve the error messages or provide additional validation:
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_02_validate.md")]
//!
//! ### Argument Relations
//!
//! You can declare dependencies or conflicts between [`Arg`][crate::Arg]s or even
//! [`ArgGroup`][crate::ArgGroup]s.
//!
//! [`ArgGroup`][crate::ArgGroup]s  make it easier to declare relations instead of having to list
//! each individually, or when you want a rule to apply "any but not all" arguments.
//!
//! Perhaps the most common use of [`ArgGroup`][crate::ArgGroup]s is to require one and *only* one
//! argument to be present out of a given set. Imagine that you had multiple arguments, and you
//! want one of them to be required, but making all of them required isn't feasible because perhaps
//! they conflict with each other.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_03_relations.md")]
//!
//! ### Custom Validation
//!
//! As a last resort, you can create custom errors with the basics of clap's formatting.
//!
//! ```rust
#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.rs")]
//! ```
#![doc = include_str!("../../examples/tutorial_derive/04_04_custom.md")]
//!
//! ## Testing
//!
//! clap reports most development errors as `debug_assert!`s.  Rather than checking every
//! subcommand, you should have a test that calls
//! [`Command::debug_assert`][crate::Command::debug_assert]:
//! ```rust,no_run
#![doc = include_str!("../../examples/tutorial_derive/05_01_assert.rs")]
//! ```
<|endoftext|>