<commit_before>use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => println!("{}", why),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
                // assumes 64-bit pointers (in file as well as on platform)
                loop {
                    // read_file_dna
                    let mut bhead8 = [0u8, ..24]; // 4 * int + 64-bit pointer
                    match file.read(bhead8) {
                        Err(why) => println!("{}", why),
                        Ok(_) => (),
                    }
                    // pack those 24 bytes into a string ...
                    let mut bhead = String::new();
                    for n in range(0u, 24) {
                        bhead.push(bhead8[n] as char);
                    }
                    let slice = bhead.as_slice();
                    let code: &str = slice.slice(0, 4); // first 4 chars
                    println!("code = {}", code);
                    let mut len: uint = 0;
                    len += (bhead8[4] as uint) <<  0;
                    len += (bhead8[5] as uint) <<  8;
                    len += (bhead8[6] as uint) << 16;
                    len += (bhead8[7] as uint) << 24;
                    println!("len = {}", len);
                    if code == "ENDB" && len == 0 {
                        break;
                    } else if code == "DNA1" {
                        // DNA_sdna_from_data
                        let mut counter = 0u;
                        // SDNA
                        let mut char4 = [0u8, ..4];
                        match file.read(char4) {
                            Err(why) => println!("{}", why),
                            Ok(_) => (),
                        }
                        counter += 4;
                        let mut str4 = String::new();
                        for n in range(0u, 4) {
                            str4.push(char4[n] as char);
                        }
                        let slice = str4.as_slice();
                        let code: &str = slice.slice(0, 4);
                        println!("  code = {}", code);
                        if code == "SDNA" {
                            // NAME
                            let mut char4 = [0u8, ..4];
                            match file.read(char4) {
                                Err(why) => println!("{}", why),
                                Ok(_) => (),
                            }
                            counter += 4;
                            let mut str4 = String::new();
                            for n in range(0u, 4) {
                                str4.push(char4[n] as char);
                            }
                            let slice = str4.as_slice();
                            let code: &str = slice.slice(0, 4);
                            println!("  code = {}", code);
                            if code == "NAME" {
                                // nr_names
                                let io_result = file.read_le_u32();
                                let nr_names: u32 = io_result.unwrap();
                                counter += 4;
                                println!("  nr_names = {}", nr_names);
                                let mut nr = 0u32;
                                loop {
                                    let mut name = String::new();
                                    loop {
                                        // expect strings with '\0' as terminator
                                        let io_result = file.read_byte();
                                        let byte: u8 = io_result.unwrap();
                                        counter += 1;
                                        if byte != 0 {
                                            name.push(byte as char);
                                        } else {
                                            println!("    name = '{}'", name);
                                            nr += 1;
                                            break;
                                        }
                                    } // name loop
                                    if nr >= nr_names {
                                        break;
                                    }
                                } // nr_names loop
                                // assume fill bytes with '\0'
                                let mut last_byte;
                                loop {
                                    let io_result = file.read_byte();
                                    let byte: u8 = io_result.unwrap();
                                    counter += 1;
                                    if byte != 0 {
                                        last_byte = byte;
                                        break;
                                    }
                                } // fill bytes
                                // TYPE
                                let mut char3 = [0u8, ..3];
                                match file.read(char3) {
                                    Err(why) => println!("{}", why),
                                    Ok(_) => (),
                                }
                                counter += 3;
                                let mut str4 = String::new();
                                str4.push(last_byte as char);
                                for n in range(0u, 3) {
                                    str4.push(char3[n] as char);
                                }
                                let slice = str4.as_slice();
                                let code: &str = slice.slice(0, 4);
                                println!("  code = {}", code);
                                if code == "TYPE" {
                                    // nr_types
                                    let io_result = file.read_le_u32();
                                    let nr_types: u32 = io_result.unwrap();
                                    counter += 4;
                                    println!("  nr_types = {}", nr_types);
                                    let mut nr = 0u32;
                                    loop {
                                        let mut name = String::new();
                                        loop {
                                            // expect strings with
                                            // '\0' as terminator
                                            let io_result = file.read_byte();
                                            let byte: u8 = io_result.unwrap();
                                            counter += 1;
                                            if byte != 0 {
                                                name.push(byte as char);
                                            } else {
                                                println!("    type = '{}'",
                                                         name);
                                                nr += 1;
                                                break;
                                            }
                                        } // type loop
                                        if nr >= nr_types {
                                            break;
                                        }
                                    } // nr_types loop
                                    // assume fill bytes with '\0'
                                    let mut last_byte;
                                    loop {
                                        let io_result = file.read_byte();
                                        let byte: u8 = io_result.unwrap();
                                        counter += 1;
                                        if byte != 0 {
                                            last_byte = byte;
                                            break;
                                        }
                                    } // fill bytes
                                    // TLEN
                                    let mut char3 = [0u8, ..3];
                                    match file.read(char3) {
                                        Err(why) => println!("{}", why),
                                        Ok(_) => (),
                                    }
                                    counter += 3;
                                    let mut str4 = String::new();
                                    str4.push(last_byte as char);
                                    for n in range(0u, 3) {
                                        str4.push(char3[n] as char);
                                    }
                                    let slice = str4.as_slice();
                                    let code: &str = slice.slice(0, 4);
                                    println!("  code = {}", code);
                                    if code == "TLEN" {
                                        // typelens
                                        let io_result = file.read_le_u16();
                                        let typelens: u16 = io_result.unwrap();
                                        counter += 2;
                                        println!("    typelens = {}", typelens);
                                        // skip nr_types times u16 values
                                        let _dummy = file.read_exact(2u *
                                                                     nr_types as
                                                                     uint);
                                        counter += 2u * nr_types as uint;
                                        // check next byte
                                        let io_result = file.read_byte();
                                        last_byte = io_result.unwrap();
                                        counter += 1;
                                        if last_byte == 0 {
                                            let io_result = file.read_byte();
                                            last_byte = io_result.unwrap();
                                            counter += 1;
                                        }
                                        // STRC
                                        let mut char3 = [0u8, ..3];
                                        match file.read(char3) {
                                            Err(why) => println!("{}", why),
                                            Ok(_) => (),
                                        }
                                        counter += 3;
                                        let mut str4 = String::new();
                                        str4.push(last_byte as char);
                                        for n in range(0u, 3) {
                                            str4.push(char3[n] as char);
                                        }
                                        let slice = str4.as_slice();
                                        let code: &str = slice.slice(0, 4);
                                        println!("  code = {}", code);
                                        if code == "STRC" {
                                            // nr_structs
                                            let io_result = file.read_le_u32();
                                            let nr_structs: u32 = io_result.unwrap();
                                            counter += 4;
                                            println!("    nr_structs = {}", nr_structs);
                                            nr = 0u32;
                                            loop {
                                                // sp0
                                                let io_result = file.read_le_u16();
                                                let _sp0: u16 = io_result.unwrap();
                                                counter += 2;
                                                // sp1
                                                let io_result = file.read_le_u16();
                                                let sp1: u16 = io_result.unwrap();
                                                counter += 2;
                                                for _n in range(0u16, 2 * sp1) {
                                                    let io_result = file.read_le_u16();
                                                    let _u: u16 = io_result.unwrap();
                                                    counter += 2;
                                                }
                                                nr += 1;
                                                if nr >= nr_structs {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        // read remaining stuff
                        println!("skip {} bytes", len - counter)
                        let _dummy = file.read_exact(len - counter);
                    } else {
                        let _dummy = file.read_exact(len);
                    }
                }
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<commit_msg>Extract camera data (name, type, lens) from Blender file.<commit_after>use std::io::File;
use std::mem;
use std::os;

// https://stackoverflow.com/questions/24633784/is-there-a-gzip-library-available-for-rust

fn pointer_size() -> uint {
    let tmp = 0u8;
    let boxed = box tmp;
    mem::size_of_val(&boxed)
}

fn main() {
    let args = os::args();
    if args.len() != 2 {
        println!("usage: read_blend_file /path/to/file.blend");
    } else {
        let slice: &str = args[1].as_slice();
        println!("open \"{}\" ...", slice);
        {
            // read 12 bytes from the Blender file
            let path = Path::new(slice);
            let display = path.display();
            let mut file = match File::open(&path) {
                Err(why) => fail!("couldn't open {}: {}", display, why.desc),
                Ok(file) => file,
            };
            let mut buf = [0u8, ..12];
            match file.read(buf) {
                Err(why) => println!("{}", why),
                Ok(_) => (),
            }
            // pack those 12 bytes into a string ...
            let mut header = String::new();
            for n in range(0u, 12) {
                header.push(buf[n] as char);
            }
            // ... to be able to compare them
            let slice = header.as_slice();
            let blender: &str = slice.slice(0, 7); // first 7 chars
            if blender == "BLENDER" {
                println!("INFO: a Blender file.");
                let ptr_size = pointer_size();
                println!("size of pointer in bytes: {}", ptr_size);
                println!("Header (12 chars): {}", header);
                let mut ptr_size_differs = false;
                if buf[7] as char == '_' {
                    // 32-bit pointers expected
                    if ptr_size != 4 {
                        ptr_size_differs = true;
                    }
                    println!("32-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                } else {
                    // 64-bit pointers expected
                    if ptr_size != 8 {
                        ptr_size_differs = true;
                    }
                    println!("64-bit pointers in file, pointer size differs? {}", ptr_size_differs);
                }
                // little endian or big endian?
                let mut l_endian;
                let endian_test = 1u16; // value one stored in two bytes
                if endian_test.to_le() != endian_test {
                    l_endian = false;
                } else {
                    // if we are on a little endian machine to_le() is a no-op
                    l_endian = true;
                }
                println!("l_endian = {}", l_endian);
                let mut switch_endian;
                if buf[8] as char == 'v' {
                    // file stores little endian
                    if !l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                } else {
                    // file stores big endian
                    if l_endian {
                        switch_endian = true;
                    } else {
                        switch_endian = false;
                    }
                }
                println!("switch_endian = {}", switch_endian);
                // get the version number
                let mut num = String::new();
                for n in range(9u, 12) {
                    num.push(buf[n] as char);
                }
                println!("num = {}", num);
                // assumes 64-bit pointers (in file as well as on platform)
                loop {
                    // read_file_dna
                    let mut bhead8 = [0u8, ..24]; // 4 * int + 64-bit pointer
                    match file.read(bhead8) {
                        Err(why) => println!("{}", why),
                        Ok(_) => (),
                    }
                    // pack those 24 bytes into a string ...
                    let mut bhead = String::new();
                    for n in range(0u, 24) {
                        bhead.push(bhead8[n] as char);
                    }
                    let slice = bhead.as_slice();
                    let code: &str = slice.slice(0, 4); // first 4 chars
                    println!("code = {}", code);
                    let mut len: uint = 0;
                    len += (bhead8[4] as uint) <<  0;
                    len += (bhead8[5] as uint) <<  8;
                    len += (bhead8[6] as uint) << 16;
                    len += (bhead8[7] as uint) << 24;
                    println!("len = {}", len);
                    if code == "ENDB" && len == 0 {
                        break;
                    } else if code == "DNA1" {
                        // DNA_sdna_from_data
                        let mut counter = 0u;
                        // SDNA
                        let mut char4 = [0u8, ..4];
                        match file.read(char4) {
                            Err(why) => println!("{}", why),
                            Ok(_) => (),
                        }
                        counter += 4;
                        let mut str4 = String::new();
                        for n in range(0u, 4) {
                            str4.push(char4[n] as char);
                        }
                        let slice = str4.as_slice();
                        let code: &str = slice.slice(0, 4);
                        println!("  code = {}", code);
                        if code == "SDNA" {
                            // NAME
                            let mut char4 = [0u8, ..4];
                            match file.read(char4) {
                                Err(why) => println!("{}", why),
                                Ok(_) => (),
                            }
                            counter += 4;
                            let mut str4 = String::new();
                            for n in range(0u, 4) {
                                str4.push(char4[n] as char);
                            }
                            let slice = str4.as_slice();
                            let code: &str = slice.slice(0, 4);
                            println!("  code = {}", code);
                            if code == "NAME" {
                                // nr_names
                                let io_result = file.read_le_u32();
                                let nr_names: u32 = io_result.unwrap();
                                counter += 4;
                                println!("  nr_names = {}", nr_names);
                                let mut nr = 0u32;
                                loop {
                                    let mut name = String::new();
                                    loop {
                                        // expect strings with '\0' as terminator
                                        let io_result = file.read_byte();
                                        let byte: u8 = io_result.unwrap();
                                        counter += 1;
                                        if byte != 0 {
                                            name.push(byte as char);
                                        } else {
                                            println!("    name = '{}'", name);
                                            nr += 1;
                                            break;
                                        }
                                    } // name loop
                                    if nr >= nr_names {
                                        break;
                                    }
                                } // nr_names loop
                                // assume fill bytes with '\0'
                                let mut last_byte;
                                loop {
                                    let io_result = file.read_byte();
                                    let byte: u8 = io_result.unwrap();
                                    counter += 1;
                                    if byte != 0 {
                                        last_byte = byte;
                                        break;
                                    }
                                } // fill bytes
                                // TYPE
                                let mut char3 = [0u8, ..3];
                                match file.read(char3) {
                                    Err(why) => println!("{}", why),
                                    Ok(_) => (),
                                }
                                counter += 3;
                                let mut str4 = String::new();
                                str4.push(last_byte as char);
                                for n in range(0u, 3) {
                                    str4.push(char3[n] as char);
                                }
                                let slice = str4.as_slice();
                                let code: &str = slice.slice(0, 4);
                                println!("  code = {}", code);
                                if code == "TYPE" {
                                    // nr_types
                                    let io_result = file.read_le_u32();
                                    let nr_types: u32 = io_result.unwrap();
                                    counter += 4;
                                    println!("  nr_types = {}", nr_types);
                                    let mut nr = 0u32;
                                    loop {
                                        let mut name = String::new();
                                        loop {
                                            // expect strings with
                                            // '\0' as terminator
                                            let io_result = file.read_byte();
                                            let byte: u8 = io_result.unwrap();
                                            counter += 1;
                                            if byte != 0 {
                                                name.push(byte as char);
                                            } else {
                                                println!("    type = '{}'",
                                                         name);
                                                nr += 1;
                                                break;
                                            }
                                        } // type loop
                                        if nr >= nr_types {
                                            break;
                                        }
                                    } // nr_types loop
                                    // assume fill bytes with '\0'
                                    let mut last_byte;
                                    loop {
                                        let io_result = file.read_byte();
                                        let byte: u8 = io_result.unwrap();
                                        counter += 1;
                                        if byte != 0 {
                                            last_byte = byte;
                                            break;
                                        }
                                    } // fill bytes
                                    // TLEN
                                    let mut char3 = [0u8, ..3];
                                    match file.read(char3) {
                                        Err(why) => println!("{}", why),
                                        Ok(_) => (),
                                    }
                                    counter += 3;
                                    let mut str4 = String::new();
                                    str4.push(last_byte as char);
                                    for n in range(0u, 3) {
                                        str4.push(char3[n] as char);
                                    }
                                    let slice = str4.as_slice();
                                    let code: &str = slice.slice(0, 4);
                                    println!("  code = {}", code);
                                    if code == "TLEN" {
                                        // typelens
                                        let io_result = file.read_le_u16();
                                        let typelens: u16 = io_result.unwrap();
                                        counter += 2;
                                        println!("    typelens = {}", typelens);
                                        // skip nr_types times u16 values
                                        let _dummy = file.read_exact(2u *
                                                                     nr_types as
                                                                     uint);
                                        counter += 2u * nr_types as uint;
                                        // check next byte
                                        let io_result = file.read_byte();
                                        last_byte = io_result.unwrap();
                                        counter += 1;
                                        if last_byte == 0 {
                                            let io_result = file.read_byte();
                                            last_byte = io_result.unwrap();
                                            counter += 1;
                                        }
                                        // STRC
                                        let mut char3 = [0u8, ..3];
                                        match file.read(char3) {
                                            Err(why) => println!("{}", why),
                                            Ok(_) => (),
                                        }
                                        counter += 3;
                                        let mut str4 = String::new();
                                        str4.push(last_byte as char);
                                        for n in range(0u, 3) {
                                            str4.push(char3[n] as char);
                                        }
                                        let slice = str4.as_slice();
                                        let code: &str = slice.slice(0, 4);
                                        println!("  code = {}", code);
                                        if code == "STRC" {
                                            // nr_structs
                                            let io_result = file.read_le_u32();
                                            let nr_structs: u32 = io_result.unwrap();
                                            counter += 4;
                                            println!("    nr_structs = {}", nr_structs);
                                            nr = 0u32;
                                            loop {
                                                // sp0
                                                let io_result = file.read_le_u16();
                                                let _sp0: u16 = io_result.unwrap();
                                                counter += 2;
                                                // sp1
                                                let io_result = file.read_le_u16();
                                                let sp1: u16 = io_result.unwrap();
                                                counter += 2;
                                                for _n in range(0u16, 2 * sp1) {
                                                    let io_result = file.read_le_u16();
                                                    let _u: u16 = io_result.unwrap();
                                                    counter += 2;
                                                }
                                                nr += 1;
                                                if nr >= nr_structs {
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        // read remaining stuff
                        println!("skip {} bytes", len - counter)
                        let _dummy = file.read_exact(len - counter);
                    } else {
                        let tc: &str = slice.slice(0, 2); // first 2 chars
                        if tc == "CA" {
                            let mut counter = 0u;
                            // struct ID (see DNA_ID.h)
                            let _next = file.read_le_u64();
                            counter += 8;
                            let _prev = file.read_le_u64();
                            counter += 8;
                            let _newid = file.read_le_u64();
                            counter += 8;
                            let _lib = file.read_le_u64();
                            counter += 8;
                            let mut bname = [0u8, ..66];
                            match file.read(bname) {
                                Err(why) => println!("{}", why),
                                Ok(_) => (),
                            }
                            // pack those 66 bytes into a string ...
                            let mut name = String::new();
                            for n in range(0u, 66) {
                                if bname[n] == 0u8 {
                                    // ... but stop as soon as you see '\0'
                                    break;
                                } else {
                                    name.push(bname[n] as char);
                                }
                            }
                            counter += 66;
                            let _flag = file.read_le_u16();
                            counter += 2;
                            let _us = file.read_le_u32();
                            counter += 4;
                            let _icon_id = file.read_le_u32();
                            counter += 4;
                            let _pad2 = file.read_le_u32();
                            counter += 4;
                            let _properties = file.read_le_u64();
                            counter += 8;
                            // struct Camera (see DNA_camera_types.h)
                            let _adt = file.read_le_u64();
                            counter += 8;
                            let io_result = file.read_u8();
                            let cam_type: u8 = io_result.unwrap();
                            counter += 1;
                            let _dtx = file.read_u8();
                            counter += 1;
                            let _flag = file.read_le_u16();
                            counter += 2;
                            let _passepartalpha = file.read_le_f32();
                            counter += 4;
                            let _clipsta = file.read_le_f32();
                            counter += 4;
                            let _clipend = file.read_le_f32();
                            counter += 4;
                            let io_result = file.read_le_f32();
                            let lens: f32 = io_result.unwrap();
                            counter += 4;
                            let _dummy = file.read_exact(len - counter);
                            if cam_type == 0u8 {
                                println!("Camera({}, {}, {})", name, "CAM_PERSP", lens)
                            } else {
                                println!("Camera({}, {}, {})", name, cam_type, lens)
                            }
                        } else {
                            let _dummy = file.read_exact(len);
                        }
                    }
                }
            } else {
                println!("ERROR: not a Blender file.");
            }
        } // file gets closed here
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix broken Debug Pogo logic (#108)<commit_after><|endoftext|>


<commit_before><commit_msg>thermostat<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the hover feature

use crate::{
    lsp_runtime_error::{LSPRuntimeError, LSPRuntimeResult},
    resolution_path::ResolvePosition,
    server::GlobalState,
};
use lsp_types::{
    request::{HoverRequest, Request},
    LanguageString, MarkedString,
};
use serde::Serialize;

mod with_resolution_path;
use with_resolution_path::get_hover;

pub use self::with_resolution_path::ContentConsumerType;

fn graphql_marked_string(value: String) -> MarkedString {
    MarkedString::LanguageString(LanguageString {
        language: "graphql".to_string(),
        value,
    })
}

/// This will provide a more accurate information about some of the specific Relay directives
/// that cannot be expressed via SDL
fn argument_definition_hover_info(directive_name: &str) -> Option<MarkedString> {
    match directive_name {
        "argumentDefinitions" => Some(
            r#"
`@argumentDefinitions` is a directive used to specify arguments taken by a fragment.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#argumentdefinitions
"#,
        ),
        "arguments" => Some(
            r#"
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        "uncheckedArguments_DEPRECATED" => Some(
            r#"
DEPRECATED version of `@arguments` directive.
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        _ => None,
    }.map(|s| MarkedString::String(s.to_string()))
}

pub fn on_hover(
    state: &impl GlobalState,
    params: <HoverRequest as Request>::Params,
) -> LSPRuntimeResult<<HoverRequest as Request>::Result> {
    let (document, position_span) =
        state.extract_executable_document_from_text(&params.text_document_position_params, 1)?;

    let resolution_path = document.resolve((), position_span);

    let project_name = state
        .extract_project_name_from_url(&params.text_document_position_params.text_document.uri)?;

    let schema = state.get_schema(&project_name)?;

    let schema_documentation = state.get_schema_documentation(project_name.lookup());

    get_hover(
        &resolution_path,
        &schema,
        project_name,
        &*state.get_extra_data_provider(),
        &schema_documentation,
        &state.get_program(&project_name)?,
        state.get_content_consumer_type(),
    )
    .map(Option::Some)
    .ok_or(LSPRuntimeError::ExpectedError)
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct GraphQLSchemaExplorerParams<'a> {
    path: Vec<&'a str>,

    schema_name: &'a str,

    #[serde(skip_serializing_if = "Option::is_none")]
    filter: Option<&'a str>,
}

fn get_open_schema_explorer_command_link(
    text: &str,
    params: &GraphQLSchemaExplorerParams<'_>,
) -> String {
    format!(
        "[{}](command:{})",
        text,
        get_open_schema_explorer_command(params)
    )
}

fn get_open_schema_explorer_command(params: &GraphQLSchemaExplorerParams<'_>) -> String {
    // see https://docs.rs/percent-encoding/2.1.0/percent_encoding/
    use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};

    const FRAGMENT: AsciiSet = CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');

    return format!(
        "nuclide.relay-lsp.openSchemaExplorer?{}",
        utf8_percent_encode(&serde_json::to_string(params).unwrap(), &FRAGMENT)
    );
}
<commit_msg>Fixing on_hover handlers<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the hover feature

use crate::{
    lsp_runtime_error::LSPRuntimeResult, resolution_path::ResolvePosition, server::GlobalState,
};
use lsp_types::{
    request::{HoverRequest, Request},
    LanguageString, MarkedString,
};
use serde::Serialize;

mod with_resolution_path;
use with_resolution_path::get_hover;

pub use self::with_resolution_path::ContentConsumerType;

fn graphql_marked_string(value: String) -> MarkedString {
    MarkedString::LanguageString(LanguageString {
        language: "graphql".to_string(),
        value,
    })
}

/// This will provide a more accurate information about some of the specific Relay directives
/// that cannot be expressed via SDL
fn argument_definition_hover_info(directive_name: &str) -> Option<MarkedString> {
    match directive_name {
        "argumentDefinitions" => Some(
            r#"
`@argumentDefinitions` is a directive used to specify arguments taken by a fragment.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#argumentdefinitions
"#,
        ),
        "arguments" => Some(
            r#"
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        "uncheckedArguments_DEPRECATED" => Some(
            r#"
DEPRECATED version of `@arguments` directive.
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

---
@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        _ => None,
    }.map(|s| MarkedString::String(s.to_string()))
}

pub fn on_hover(
    state: &impl GlobalState,
    params: <HoverRequest as Request>::Params,
) -> LSPRuntimeResult<<HoverRequest as Request>::Result> {
    let (document, position_span) =
        state.extract_executable_document_from_text(&params.text_document_position_params, 1)?;

    let resolution_path = document.resolve((), position_span);

    let project_name = state
        .extract_project_name_from_url(&params.text_document_position_params.text_document.uri)?;

    let schema = state.get_schema(&project_name)?;

    let schema_documentation = state.get_schema_documentation(project_name.lookup());

    Ok(get_hover(
        &resolution_path,
        &schema,
        project_name,
        &*state.get_extra_data_provider(),
        &schema_documentation,
        &state.get_program(&project_name)?,
        state.get_content_consumer_type(),
    ))
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct GraphQLSchemaExplorerParams<'a> {
    path: Vec<&'a str>,

    schema_name: &'a str,

    #[serde(skip_serializing_if = "Option::is_none")]
    filter: Option<&'a str>,
}

fn get_open_schema_explorer_command_link(
    text: &str,
    params: &GraphQLSchemaExplorerParams<'_>,
) -> String {
    format!(
        "[{}](command:{})",
        text,
        get_open_schema_explorer_command(params)
    )
}

fn get_open_schema_explorer_command(params: &GraphQLSchemaExplorerParams<'_>) -> String {
    // see https://docs.rs/percent-encoding/2.1.0/percent_encoding/
    use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};

    const FRAGMENT: AsciiSet = CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').add(b'`');

    return format!(
        "nuclide.relay-lsp.openSchemaExplorer?{}",
        utf8_percent_encode(&serde_json::to_string(params).unwrap(), &FRAGMENT)
    );
}
<|endoftext|>


<commit_before>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};
use std::iter;

#[derive(Debug)]
pub struct StyledBuffer {
    text: Vec<Vec<char>>,
    styles: Vec<Vec<Style>>,
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { text: vec![], styles: vec![] }
    }

    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.text.iter().all(|r| !r.contains(&'\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for (row, row_style) in iter::zip(&self.text, &self.styles) {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for (&c, &s) in iter::zip(row, row_style) {
                if s != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = s;
                    current_text = String::new();
                }
                current_text.push(c);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        while line >= self.text.len() {
            self.text.push(vec![]);
            self.styles.push(vec![]);
        }
    }

    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col < self.text[line].len() {
            self.text[line][col] = chr;
            self.styles[line][col] = style;
        } else {
            let mut i = self.text[line].len();
            while i < col {
                self.text[line].push(' ');
                self.styles[line].push(Style::NoStyle);
                i += 1;
            }
            self.text[line].push(chr);
            self.styles[line].push(style);
        }
    }

    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        // Push the old content over to make room for new content
        for _ in 0..string_len {
            self.styles[line].insert(0, Style::NoStyle);
            self.text[line].insert(0, ' ');
        }

        self.puts(line, 0, string, style);
    }

    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.text.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.text[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.text.len()
    }

    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.styles.get_mut(line) {
            if let Some(s) = line.get_mut(col) {
                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
                    *s = style;
                }
            }
        }
    }
}
<commit_msg>Rollup merge of #84235 - klensy:styled-buffer, r=lcnr<commit_after>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};

#[derive(Debug)]
pub struct StyledBuffer {
    lines: Vec<Vec<StyledChar>>,
}

#[derive(Debug, Clone)]
struct StyledChar {
    chr: char,
    style: Style,
}

impl StyledChar {
    const SPACE: Self = StyledChar::new(' ', Style::NoStyle);

    const fn new(chr: char, style: Style) -> Self {
        StyledChar { chr, style }
    }
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { lines: vec![] }
    }

    /// Returns content of `StyledBuffer` splitted by lines and line styles
    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for styled_line in &self.lines {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for sc in styled_line {
                if sc.style != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = sc.style;
                    current_text = String::new();
                }
                current_text.push(sc.chr);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        if line >= self.lines.len() {
            self.lines.resize(line + 1, Vec::new());
        }
    }

    /// Sets `chr` with `style` for given `line`, `col`.
    /// If `line` does not exist in our buffer, adds empty lines up to the given
    /// and fills the last line with unstyled whitespace.
    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col >= self.lines[line].len() {
            self.lines[line].resize(col + 1, StyledChar::SPACE);
        }
        self.lines[line][col] = StyledChar::new(chr, style);
    }

    /// Sets `string` with `style` for given `line`, starting from `col`.
    /// If `line` does not exist in our buffer, adds empty lines up to the given
    /// and fills the last line with unstyled whitespace.
    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    /// For given `line` inserts `string` with `style` before old content of that line,
    /// adding lines if needed
    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        if !self.lines[line].is_empty() {
            // Push the old content over to make room for new content
            for _ in 0..string_len {
                self.lines[line].insert(0, StyledChar::SPACE);
            }
        }

        self.puts(line, 0, string, style);
    }

    /// For given `line` inserts `string` with `style` after old content of that line,
    /// adding lines if needed
    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.lines.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.lines[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.lines.len()
    }

    /// Set `style` for `line`, `col_start..col_end` range if:
    /// 1. That line and column range exist in `StyledBuffer`
    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    /// Set `style` for `line`, `col` if:
    /// 1. That line and column exist in `StyledBuffer`
    /// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.lines.get_mut(line) {
            if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
                if overwrite || *s == Style::NoStyle || *s == Style::Quotation {
                    *s = style;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult};
use crate::throw_ub;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data;
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = truncate(u128::MAX, Size::from_bytes(size));
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

/// The raw bytes of a simple value.
///
/// This is a packed struct in order to allow this type to be optimally embedded in enums
/// (like Scalar).
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(packed)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    data: u128,
    size: u8,
}

// Cannot derive these, as the derives take references to the fields, and we
// can't take references to fields of packed structs.
impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
        // Since `Self` is a packed struct, that would create a possibly unaligned reference,
        // which is UB on a lot of platforms.
        { self.data }.hash_stable(hcx, hasher);
        self.size.hash_stable(hcx, hasher);
    }
}

impl<S: Encoder> Encodable<S> for ScalarInt {
    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u128(self.data)?;
        s.emit_u8(self.size)
    }
}

impl<D: Decoder> Decodable<D> for ScalarInt {
    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
        Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
    }
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };

    pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but since the enum variants are public,
    /// it could still be violated (even though no code outside this file should
    /// construct `Scalar`s).
    #[inline(always)]
    fn check_data(self) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `assert_eq` takes references to its arguments and formatting
        // arguments and would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB on a lot of platforms.
        debug_assert_eq!(
            truncate(self.data, self.size()),
            { self.data },
            "Scalar value {:#x} exceeds size of {} bytes",
            { self.data },
            self.size
        );
    }

    #[inline]
    pub fn zst() -> Self {
        Self::null(Size::ZERO)
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { data: 0, size: size.bytes() as u8 }
    }

    pub(crate) fn ptr_sized_op<'tcx>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
    ) -> InterpResult<'tcx, Self> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self { data: u128::from(f_int(u64::try_from(self.data).unwrap())?), size: self.size })
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if truncate(data, size) == data {
            Some(Self { data, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        if sign_extend(truncated, size) as i128 == i {
            Some(Self { data: truncated, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        assert_eq!(target_size.bytes(), u64::from(self.size));
        self.check_data();
        self.data
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() != u64::from(self.size) {
            throw_ub!(ScalarSizeMismatch {
                target_size: target_size.bytes(),
                data_size: u64::from(self.size),
            });
        }
        self.check_data();
        Ok(self.data)
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        data: u128::from(u),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = InterpErrorInfo<'static>;
                #[inline]
                fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB on a lot of platforms.
        write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
    }
}

impl fmt::UpperHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB on a lot of platforms.
        write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
    }
}
<commit_msg>Unaligned reads are UB in Rust irrelevant on which platform we are<commit_after>use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult};
use crate::throw_ub;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
use std::fmt;

#[derive(Copy, Clone)]
/// A type for representing any integer. Only used for printing.
pub struct ConstInt {
    /// The "untyped" variant of `ConstInt`.
    int: ScalarInt,
    /// Whether the value is of a signed integer type.
    signed: bool,
    /// Whether the value is a `usize` or `isize` type.
    is_ptr_sized_integral: bool,
}

impl ConstInt {
    pub fn new(int: ScalarInt, signed: bool, is_ptr_sized_integral: bool) -> Self {
        Self { int, signed, is_ptr_sized_integral }
    }
}

impl std::fmt::Debug for ConstInt {
    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let Self { int, signed, is_ptr_sized_integral } = *self;
        let size = int.size().bytes();
        let raw = int.data;
        if signed {
            let bit_size = size * 8;
            let min = 1u128 << (bit_size - 1);
            let max = min - 1;
            if raw == min {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MIN"),
                    (1, _) => write!(fmt, "i8::MIN"),
                    (2, _) => write!(fmt, "i16::MIN"),
                    (4, _) => write!(fmt, "i32::MIN"),
                    (8, _) => write!(fmt, "i64::MIN"),
                    (16, _) => write!(fmt, "i128::MIN"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "isize::MAX"),
                    (1, _) => write!(fmt, "i8::MAX"),
                    (2, _) => write!(fmt, "i16::MAX"),
                    (4, _) => write!(fmt, "i32::MAX"),
                    (8, _) => write!(fmt, "i64::MAX"),
                    (16, _) => write!(fmt, "i128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as i8)?,
                    2 => write!(fmt, "{}", raw as i16)?,
                    4 => write!(fmt, "{}", raw as i32)?,
                    8 => write!(fmt, "{}", raw as i64)?,
                    16 => write!(fmt, "{}", raw as i128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_isize")?,
                        (1, _) => write!(fmt, "_i8")?,
                        (2, _) => write!(fmt, "_i16")?,
                        (4, _) => write!(fmt, "_i32")?,
                        (8, _) => write!(fmt, "_i64")?,
                        (16, _) => write!(fmt, "_i128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        } else {
            let max = truncate(u128::MAX, Size::from_bytes(size));
            if raw == max {
                match (size, is_ptr_sized_integral) {
                    (_, true) => write!(fmt, "usize::MAX"),
                    (1, _) => write!(fmt, "u8::MAX"),
                    (2, _) => write!(fmt, "u16::MAX"),
                    (4, _) => write!(fmt, "u32::MAX"),
                    (8, _) => write!(fmt, "u64::MAX"),
                    (16, _) => write!(fmt, "u128::MAX"),
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
            } else {
                match size {
                    1 => write!(fmt, "{}", raw as u8)?,
                    2 => write!(fmt, "{}", raw as u16)?,
                    4 => write!(fmt, "{}", raw as u32)?,
                    8 => write!(fmt, "{}", raw as u64)?,
                    16 => write!(fmt, "{}", raw as u128)?,
                    _ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
                }
                if fmt.alternate() {
                    match (size, is_ptr_sized_integral) {
                        (_, true) => write!(fmt, "_usize")?,
                        (1, _) => write!(fmt, "_u8")?,
                        (2, _) => write!(fmt, "_u16")?,
                        (4, _) => write!(fmt, "_u32")?,
                        (8, _) => write!(fmt, "_u64")?,
                        (16, _) => write!(fmt, "_u128")?,
                        _ => bug!(),
                    }
                }
                Ok(())
            }
        }
    }
}

/// The raw bytes of a simple value.
///
/// This is a packed struct in order to allow this type to be optimally embedded in enums
/// (like Scalar).
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(packed)]
pub struct ScalarInt {
    /// The first `size` bytes of `data` are the value.
    /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
    data: u128,
    size: u8,
}

// Cannot derive these, as the derives take references to the fields, and we
// can't take references to fields of packed structs.
impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `hash_stable` takes `&self` and would thus borrow `self.data`.
        // Since `Self` is a packed struct, that would create a possibly unaligned reference,
        // which is UB.
        { self.data }.hash_stable(hcx, hasher);
        self.size.hash_stable(hcx, hasher);
    }
}

impl<S: Encoder> Encodable<S> for ScalarInt {
    fn encode(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u128(self.data)?;
        s.emit_u8(self.size)
    }
}

impl<D: Decoder> Decodable<D> for ScalarInt {
    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
        Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
    }
}

impl ScalarInt {
    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };

    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };

    pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };

    #[inline]
    pub fn size(self) -> Size {
        Size::from_bytes(self.size)
    }

    /// Make sure the `data` fits in `size`.
    /// This is guaranteed by all constructors here, but since the enum variants are public,
    /// it could still be violated (even though no code outside this file should
    /// construct `Scalar`s).
    #[inline(always)]
    fn check_data(self) {
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `assert_eq` takes references to its arguments and formatting
        // arguments and would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        debug_assert_eq!(
            truncate(self.data, self.size()),
            { self.data },
            "Scalar value {:#x} exceeds size of {} bytes",
            { self.data },
            self.size
        );
    }

    #[inline]
    pub fn zst() -> Self {
        Self::null(Size::ZERO)
    }

    #[inline]
    pub fn null(size: Size) -> Self {
        Self { data: 0, size: size.bytes() as u8 }
    }

    pub(crate) fn ptr_sized_op<'tcx>(
        self,
        dl: &TargetDataLayout,
        f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
    ) -> InterpResult<'tcx, Self> {
        assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
        Ok(Self { data: u128::from(f_int(u64::try_from(self.data).unwrap())?), size: self.size })
    }

    #[inline]
    pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
        let data = i.into();
        if truncate(data, size) == data {
            Some(Self { data, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        if sign_extend(truncated, size) as i128 == i {
            Some(Self { data: truncated, size: size.bytes() as u8 })
        } else {
            None
        }
    }

    #[inline]
    pub fn assert_bits(self, target_size: Size) -> u128 {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        assert_eq!(target_size.bytes(), u64::from(self.size));
        self.check_data();
        self.data
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> InterpResult<'static, u128> {
        assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
        if target_size.bytes() != u64::from(self.size) {
            throw_ub!(ScalarSizeMismatch {
                target_size: target_size.bytes(),
                data_size: u64::from(self.size),
            });
        }
        self.check_data();
        Ok(self.data)
    }
}

macro_rules! from {
    ($($ty:ty),*) => {
        $(
            impl From<$ty> for ScalarInt {
                #[inline]
                fn from(u: $ty) -> Self {
                    Self {
                        data: u128::from(u),
                        size: std::mem::size_of::<$ty>() as u8,
                    }
                }
            }
        )*
    }
}

macro_rules! try_from {
    ($($ty:ty),*) => {
        $(
            impl TryFrom<ScalarInt> for $ty {
                type Error = InterpErrorInfo<'static>;
                #[inline]
                fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
                    int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())).map(|u| u.try_into().unwrap())
                }
            }
        )*
    }
}

from!(u8, u16, u32, u64, u128, bool);
try_from!(u8, u16, u32, u64, u128);

impl From<char> for ScalarInt {
    #[inline]
    fn from(c: char) -> Self {
        Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
    }
}

impl TryFrom<ScalarInt> for char {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(std::mem::size_of::<char>()))
            .map(|u| char::from_u32(u.try_into().unwrap()).unwrap())
    }
}

impl From<Single> for ScalarInt {
    #[inline]
    fn from(f: Single) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 4 }
    }
}

impl TryFrom<ScalarInt> for Single {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(4)).map(Self::from_bits)
    }
}

impl From<Double> for ScalarInt {
    #[inline]
    fn from(f: Double) -> Self {
        // We trust apfloat to give us properly truncated data.
        Self { data: f.to_bits(), size: 8 }
    }
}

impl TryFrom<ScalarInt> for Double {
    type Error = InterpErrorInfo<'static>;
    #[inline]
    fn try_from(int: ScalarInt) -> InterpResult<'static, Self> {
        int.to_bits(Size::from_bytes(8)).map(Self::from_bits)
    }
}

impl fmt::Debug for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.size == 0 {
            self.check_data();
            write!(f, "<ZST>")
        } else {
            write!(f, "0x{:x}", self)
        }
    }
}

impl fmt::LowerHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
    }
}

impl fmt::UpperHex for ScalarInt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.check_data();
        // Format as hex number wide enough to fit any value of the given `size`.
        // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
        // Using a block `{self.data}` here to force a copy instead of using `self.data`
        // directly, because `write!` takes references to its formatting arguments and
        // would thus borrow `self.data`. Since `Self`
        // is a packed struct, that would create a possibly unaligned reference, which
        // is UB.
        write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
    }
}
<|endoftext|>