<commit_before>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export map_tile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type map_tile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type static_tile = {
    header: u32,
    width: u16,
    height: u16,
    image: ~[u16]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[map_tile], ~[static_tile]) { //TODO: Find a better return type for this
    let reader:mul_reader::mul_reader = mul_reader::mul_reader(root_path, ~"artidx.mul", ~"art.mul");

    let mut map_tiles: ~[map_tile] = ~[];
    let mut static_tiles: ~[static_tile] = ~[];

    while (reader.eof() != true) {
        let item: option::option<mul_reader::mul_record> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::mul_record = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters

            if (record_header > 0xFFFF || record_header == 0) {
                /*let maybe_map_tile: option::option<map_tile> = parse_map_tile(unwrapped);
                if option::is_some(maybe_map_tile) {
                    vec::push(map_tiles, maybe_map_tile.get());
                }*/
            } else if (record_header != 0){
                let maybe_static_tile: option::option<static_tile> = parse_static_tile(unwrapped);
                if option::is_some(maybe_static_tile) {
                    vec::push(static_tiles, maybe_static_tile.get());
                }
            }
        }
    }

    ret (map_tiles, static_tiles);
}

fn parse_map_tile(record: mul_reader::mul_record) -> option::option<map_tile> { //Interestingly, pixels seem to be 565, rather than 555

    if (vec::len(record.data) != expected_tile_size) {
        ret option::none;
    }

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));

    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    ret option::some({
        header: record_header as u32,
        image: image
    });
}
fn parse_static_tile(record: mul_reader::mul_record) -> option::option<static_tile> {
    let record_header: u32 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3)) as u32;
    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 6, 7)) as u16;
    let mut image: ~[u16] = ~[];

    if (width == 0 || height == 0 || width >= 2048 || height >= 2048) {
        ret option::none;
    }
    //Stuff all of the Offsets into an array
    let mut offsets: ~[u16] = ~[];

    for uint::range(0, height as uint) |i| {
        //Ze plan - read the offset, then loop while we're reading out runs
        vec::push(offsets, byte_helpers::bytes_to_le_uint(vec::slice(record.data, 8 + (2 * i), 9 + (2 * i))) as u16);
    };

    for offsets.each |offset| {
        let row_start = 8 + (height as uint * 2); //Runs start at the offset plus the header, plus the table
        let mut run_start = row_start + (offset as uint * 2);
        let mut current_width = 0;

        loop {
            let run_padding = byte_helpers::bytes_to_le_uint(vec::slice(record.data, run_start, run_start + 1)) as u16;
            let run_length = byte_helpers::bytes_to_le_uint(vec::slice(record.data, run_start + 2, run_start + 3)) as u16;
            if run_padding == 0 && run_length == 0 {
                break;
            }
            current_width += (run_padding + run_length);
            if (current_width > width) {
                ret option::none;
            }

            if (current_width > 1024) {
                ret option::none;
            }
            //Add the padding!
            vec::grow(image, run_padding as uint, transparent);
            //Read ze pixels!
            let run_data = vec::slice(record.data, run_start + 4, run_start + 4 + (run_length as uint * 2));
            vec::push_all(image, byte_helpers::u8vec_to_u16vec(run_data));

            //io::println(#fmt("%u, %u", run_padding as uint, run_length as uint));
            run_start += 4 + (run_length * 2) as uint;
        }
        //io::println("ROW END");
        vec::grow(image, (width - current_width) as uint, transparent);
        //Pad the end of the row

    };
    //io::println("Image end");

    ret option::some({
        header: record_header as u32,
        width: width,
        height: height,
        image: image
    });
}

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    ret vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<commit_msg>Tweaked method of telling tiles<commit_after>//NOTE: apparently, when looking up statics by ID, they're offset by 0x4000.
export map_tile;
export load_tiles;
export to_bitmap;
export parse_map_tile;

type map_tile = {
    header: u32,
    image: ~[u16] //TODO: Consider making Pixel a type
};

type static_tile = {
    header: u32,
    width: u16,
    height: u16,
    image: ~[u16]
};

const transparent: u16 = 0b1000000000000000;
const expected_tile_size: uint = 2048;

fn load_tiles(root_path: ~str) -> (~[map_tile], ~[static_tile]) { //TODO: Find a better return type for this
    let reader:mul_reader::mul_reader = mul_reader::mul_reader(root_path, ~"artidx.mul", ~"art.mul");

    let mut map_tiles: ~[map_tile] = ~[];
    let mut static_tiles: ~[static_tile] = ~[];

    let mut index:uint = 0;
    while (reader.eof() != true) {
        let item: option::option<mul_reader::mul_record> = reader.read();
        if option::is_some(item) {
            let unwrapped: mul_reader::mul_record = option::get(item);
            let record_header = byte_helpers::bytes_to_le_uint(vec::slice(unwrapped.data, 0, 3));
            //Apparently, these flag values represent whether something is a tile or not
            //Others are not convinced, and think that index is all that matters

            //if (record_header > 0xFFFF || record_header == 0) {
            if (index < 0x4000) {
                /*let maybe_map_tile: option::option<map_tile> = parse_map_tile(unwrapped);
                if option::is_some(maybe_map_tile) {
                    vec::push(map_tiles, maybe_map_tile.get());
                }*/
            } else if (index < 0x8000){
                let maybe_static_tile: option::option<static_tile> = parse_static_tile(unwrapped);
                if option::is_some(maybe_static_tile) {
                    vec::push(static_tiles, maybe_static_tile.get());
                }
            }
        }
        index += 1;
    }

    ret (map_tiles, static_tiles);
}

fn parse_map_tile(record: mul_reader::mul_record) -> option::option<map_tile> { //Interestingly, pixels seem to be 565, rather than 555

    if (vec::len(record.data) != expected_tile_size) {
        ret option::none;
    }

    let record_header = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 3));

    let mut image: ~[u16] = ~[];
    let data_slice: ~[u8] = vec::slice(record.data, 4, vec::len(record.data));

    let mut data_pointer: uint = 0;
    for uint::range(0, 44) |i| {

        let slice: uint = if (i >= 22) {(44 - i) * 2} else {(i + 1) * 2};
        vec::grow(image, (22 - (slice / 2)), transparent);
        let slice_data: ~[u8] = vec::slice(data_slice, data_pointer, data_pointer + (slice * 2));
        vec::push_all(image, byte_helpers::u8vec_to_u16vec(slice_data));
        vec::grow(image, (22 - (slice / 2)), transparent);
        data_pointer += (slice * 2);
    };

    ret option::some({
        header: record_header as u32,
        image: image
    });
}
fn parse_static_tile(record: mul_reader::mul_record) -> option::option<static_tile> {
    let data_size: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 0, 1)) as u16; //Might not be size :P
    let trigger: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 2, 3)) as u16;

    let width: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 4, 5)) as u16;
    let height: u16 = byte_helpers::bytes_to_le_uint(vec::slice(record.data, 6, 7)) as u16;
    let mut image: ~[u16] = ~[];

    if (width == 0 || height == 0 || width > 1024 || height > 1024) {
        ret option::none;
    }

    //Stuff all of the Offsets into an array
    let mut offsets: ~[u16] = ~[];

    for uint::range(0, height as uint) |i| {
        //Ze plan - read the offset, then loop while we're reading out runs
        vec::push(offsets, byte_helpers::bytes_to_le_uint(vec::slice(record.data, 8 + (2 * i), 9 + (2 * i))) as u16);
    };

    let run_data_start = (height * 2) + 8;

    for offsets.each |offset| {
        let mut run_start = run_data_start + (offset * 2);
        let mut current_width = 0;

        loop {
            let run_padding = byte_helpers::bytes_to_le_uint(vec::slice(record.data, run_start as uint, run_start as uint + 1)) as u16;
            let run_length = byte_helpers::bytes_to_le_uint(vec::slice(record.data, run_start as uint + 2, run_start as uint + 3)) as u16;
            if run_length == 0 && run_padding == 0 {
                break;
            }
            current_width += (run_padding + run_length);
            if (current_width > width) {
                ret option::none;
            }

            if (current_width > 2048) {
                ret option::none;
            }
            //Add the padding!
            vec::grow(image, run_padding as uint, transparent);
            //Read ze pixels!
            let run_data = vec::slice(record.data, run_start as uint + 4, run_start as uint + 4 + (run_length as uint * 2));

            vec::push_all(image, byte_helpers::u8vec_to_u16vec(run_data));

            //io::println(#fmt("%u, %u", run_padding as uint, run_length as uint));
            run_start += 4 + (run_length * 2);
        }
        //io::println("ROW END");
        vec::grow(image, (width - current_width) as uint, transparent);
        //Pad the end of the row

    };
    //io::println("Image end");
    assert vec::len(image) == (width as uint) * (height as uint);

    ret option::some({
        header: 0,// record_header as u32,
        width: width,
        height: height,
        image: image
    });
}

fn to_bitmap(width: u32, height: u32, data: ~[u16]) -> ~[u8] { //TODO: Make this take arbitrary pixel depths
    let signature: ~[u8] = ~[0x42, 0x4D];
    let file_size: ~[u8] = byte_helpers::uint_to_le_bytes(((width * height * 2) + 14 + 40) as u64, 4);
    let reserved: ~[u8] = ~[0, 0, 0, 0];
    let data_offset: ~[u8] = byte_helpers::uint_to_le_bytes(54, 4);

    let header_size: ~[u8] = byte_helpers::uint_to_le_bytes(40, 4);
    let width_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(width as u64, 4); //FIXME: should be signed?
    let height_bytes: ~[u8] = byte_helpers::uint_to_le_bytes(height as u64, 4);
    let colour_panes: ~[u8] = ~[1, 0];
    let depth: ~[u8] = ~[16, 0];
    let compression: ~[u8] = ~[0,0,0,0];
    let image_size: ~[u8] = ~[0,0,0,0];
    let horizontal_res: ~[u8] = ~[0, 0, 0, 0];
    let vertical_res: ~[u8] = ~[0, 0, 0, 0];
    let palette_count: ~[u8] = ~[0, 0, 0, 0];
    let important_colours: ~[u8] = ~[0, 0, 0, 0];

    //54 bytes so far
    //TODO: explode the image vector, iterate backwards, turn it into bytes
    let mut rows: ~[mut ~[u8]] = ~[mut];
    for uint::range(0, height as uint) |i| {
        let slice = vec::slice(data, i * (width as uint), (i+1) * (width as uint));
        let mut row: ~[u8] = ~[];
        for slice.each |sliced| {
            vec::push_all(row, byte_helpers::uint_to_le_bytes(sliced as u64, 2));
        }
        vec::push(rows, row);
    };
    vec::reverse(rows);
    //vec::grow(pixels, 44 * 44 * 4, 0x7f);

    ret vec::concat(~[
        signature,
        file_size,
        reserved,
        data_offset,

        header_size,
        width_bytes,
        height_bytes,
        colour_panes,
        depth,
        compression,
        image_size,
        horizontal_res,
        vertical_res,
        palette_count,
        important_colours,

        vec::concat(rows)
    ]);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::i32;
use super::calculate_character_brightness::calculate_character_brightness;

#[derive(Debug)]
/// A CharacterSet represents a set of characters mapped to brightness values
pub struct CharacterSet {
    brightness_table: HashMap<i32, char>,
}

impl CharacterSet {
    // TODO generalize this so that chars is any iterable of chars
    /// Generates a new CharacterSet containing `chars`
    pub fn new(chars: Vec<char>) -> CharacterSet {
        let mut set = CharacterSet { brightness_table: HashMap::new() };
        let mut init_brightness = HashMap::new();
        let mut min = i32::MAX;
        let mut max = 0;
        for c in chars {
            let brightness = calculate_character_brightness(c);
            min = if brightness < min { brightness } else { min };
            max = if brightness > max { brightness } else { max };
            init_brightness.insert(brightness, c);
        }
        for (init_brightness, c) in init_brightness {
            let brightness = (255 * (init_brightness - min)) / (max - min);
            set.brightness_table.insert(brightness, c);
        }
        set
    }

    /// Generates a new character set from the string `string`
    pub fn from(string: &str) -> CharacterSet {
        let chars: Vec<char> = string.chars().collect();
        CharacterSet::new(chars)
    }

    /// Returns the character with brightness closest to `brightness`
    pub fn get(&self, brightness: i32) -> char {
        let mut upper = brightness;
        let mut lower = brightness;
        loop {
            match self.brightness_table.get(&upper) {
                Some(&c) => return c,
                None => upper += 1
            }
            match self.brightness_table.get(&lower) {
                Some(&c) => return c,
                None => lower -= 1
            }
        }
    }

    /// Returns a predefined CharacterSet with few characters
    pub fn preset_small() -> CharacterSet {
        CharacterSet::from("@%#x+=:-. ")
    }

    /// Returns a predefined CharacterSet with a moderate number of characters
    pub fn preset_medium() -> CharacterSet {
        CharacterSet::from("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
    }

    /// Returns a predefined CharacterSet with many characters
    pub fn preset_large() -> CharacterSet {
        CharacterSet::from("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()-_=+[{]}\\|;:'\",.<>/?")
    }
}
<commit_msg>Generalize CharacterSet::new() to take any iterable of chars<commit_after>use std::collections::HashMap;
use std::i32;
use super::calculate_character_brightness::calculate_character_brightness;

#[derive(Debug)]
/// A CharacterSet represents a set of characters mapped to brightness values
pub struct CharacterSet {
    brightness_table: HashMap<i32, char>,
}

impl CharacterSet {
    /// Generates a new CharacterSet containing `chars`
    pub fn new<T>(chars: T) -> CharacterSet where T: IntoIterator<Item=char> {
        let mut set = CharacterSet { brightness_table: HashMap::new() };
        let mut init_brightness = HashMap::new();
        let mut min = i32::MAX;
        let mut max = 0;
        for c in chars {
            let brightness = calculate_character_brightness(c);
            min = if brightness < min { brightness } else { min };
            max = if brightness > max { brightness } else { max };
            init_brightness.insert(brightness, c);
        }
        for (init_brightness, c) in init_brightness {
            let brightness = (255 * (init_brightness - min)) / (max - min);
            set.brightness_table.insert(brightness, c);
        }
        set
    }

    /// Generates a new character set from the string `string`
    pub fn from(string: &str) -> CharacterSet {
        let chars: Vec<char> = string.chars().collect();
        CharacterSet::new(chars)
    }

    /// Returns the character with brightness closest to `brightness`
    pub fn get(&self, brightness: i32) -> char {
        let mut upper = brightness;
        let mut lower = brightness;
        loop {
            match self.brightness_table.get(&upper) {
                Some(&c) => return c,
                None => upper += 1
            }
            match self.brightness_table.get(&lower) {
                Some(&c) => return c,
                None => lower -= 1
            }
        }
    }

    /// Returns a predefined CharacterSet with few characters
    pub fn preset_small() -> CharacterSet {
        CharacterSet::from("@%#x+=:-. ")
    }

    /// Returns a predefined CharacterSet with a moderate number of characters
    pub fn preset_medium() -> CharacterSet {
        CharacterSet::from("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
    }

    /// Returns a predefined CharacterSet with many characters
    pub fn preset_large() -> CharacterSet {
        CharacterSet::from("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()-_=+[{]}\\|;:'\",.<>/?")
    }
}
<|endoftext|>


<commit_before><commit_msg>enable test cases for async/await<commit_after><|endoftext|>


<commit_before>// This test case tests the incremental compilation hash (ICH) implementation
// for `extern` modules.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(rustc_attrs)]
#![feature(unboxed_closures)]
#![feature(link_args)]
#![crate_type="rlib"]

// Change function name --------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn change_function_name1(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn change_function_name2(c: i64) -> i32;
}

// Change parameter name -------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn change_parameter_name(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn change_parameter_name(d: i64) -> i32;
}

// Change parameter type -------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn change_parameter_type(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn change_parameter_type(c: i32) -> i32;
}

// Change return type ----------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn change_return_type(c: i32) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn change_return_type(c: i32) -> i8;
}

// Add parameter ---------------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn add_parameter(c: i32) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn add_parameter(c: i32, d: i32) -> i32;
}

// Add return type -------------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn add_return_type(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn add_return_type(c: i32) -> i32;
}

// Make function variadic ------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn make_function_variadic(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn make_function_variadic(c: i32, ...);
}

// Change calling convention ---------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_calling_convention(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern "rust-call" {
    pub fn change_calling_convention(c: i32);
}

// Make function public --------------------------------------------------------
#[cfg(cfail1)]
extern {
    fn make_function_public(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn make_function_public(c: i32);
}

// Add function ----------------------------------------------------------------
#[cfg(cfail1)]
extern {
    pub fn add_function1(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
extern {
    pub fn add_function1(c: i32);
    pub fn add_function2();
}

// Change link-args ------------------------------------------------------------
#[cfg(cfail1)]
#[link_args = "-foo -bar"]
extern {
    pub fn change_link_args(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[link_args = "-foo -bar -baz"]
extern {
    pub fn change_link_args(c: i32);
}

// Change link-name ------------------------------------------------------------
#[cfg(cfail1)]
#[link(name = "foo")]
extern {
    pub fn change_link_name(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg="cfail2")]
#[rustc_clean(cfg="cfail3")]
#[link(name = "bar")]
extern {
    pub fn change_link_name(c: i32);
}

type c_i32 = i32;
type c_i64 = i64;

// Indirectly change parameter type --------------------------------------------
mod indirectly_change_parameter_type {
    #[cfg(cfail1)]
    use super::c_i32 as c_int;
    #[cfg(not(cfail1))]
    use super::c_i64 as c_int;

    #[rustc_dirty(cfg="cfail2")]
    #[rustc_clean(cfg="cfail3")]
    extern {
        pub fn indirectly_change_parameter_type(c: c_int);
    }
}

// Indirectly change return type --------------------------------------------
mod indirectly_change_return_type {
    #[cfg(cfail1)]
    use super::c_i32 as c_int;
    #[cfg(not(cfail1))]
    use super::c_i64 as c_int;

    #[rustc_dirty(cfg="cfail2")]
    #[rustc_clean(cfg="cfail3")]
    extern {
        pub fn indirectly_change_return_type() -> c_int;
    }
}
<commit_msg>Update test.<commit_after>// This test case tests the incremental compilation hash (ICH) implementation
// for `extern` modules.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// build-pass (FIXME(62277): could be check-pass?)
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph -Zincremental-ignore-spans

#![allow(warnings)]
#![feature(rustc_attrs)]
#![feature(unboxed_closures)]
#![feature(link_args)]
#![crate_type = "rlib"]

// Change function name --------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_function_name1(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn change_function_name2(c: i64) -> i32;
}

// Change parameter name -------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_parameter_name(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn change_parameter_name(d: i64) -> i32;
}

// Change parameter type -------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_parameter_type(c: i64) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn change_parameter_type(c: i32) -> i32;
}

// Change return type ----------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_return_type(c: i32) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn change_return_type(c: i32) -> i8;
}

// Add parameter ---------------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn add_parameter(c: i32) -> i32;
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn add_parameter(c: i32, d: i32) -> i32;
}

// Add return type -------------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn add_return_type(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn add_return_type(c: i32) -> i32;
}

// Make function variadic ------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn make_function_variadic(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn make_function_variadic(c: i32, ...);
}

// Change calling convention ---------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn change_calling_convention(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "rust-call" {
    pub fn change_calling_convention(c: i32);
}

// Make function public --------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    fn make_function_public(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn make_function_public(c: i32);
}

// Add function ----------------------------------------------------------------
#[cfg(cfail1)]
extern "C" {
    pub fn add_function1(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
extern "C" {
    pub fn add_function1(c: i32);
    pub fn add_function2();
}

// Change link-args ------------------------------------------------------------
#[cfg(cfail1)]
#[link_args = "-foo -bar"]
extern "C" {
    pub fn change_link_args(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
#[link_args = "-foo -bar -baz"]
extern "C" {
    pub fn change_link_args(c: i32);
}

// Change link-name ------------------------------------------------------------
#[cfg(cfail1)]
#[link(name = "foo")]
extern "C" {
    pub fn change_link_name(c: i32);
}

#[cfg(not(cfail1))]
#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
#[rustc_clean(cfg = "cfail3")]
#[link(name = "bar")]
extern "C" {
    pub fn change_link_name(c: i32);
}

type c_i32 = i32;
type c_i64 = i64;

// Indirectly change parameter type --------------------------------------------
mod indirectly_change_parameter_type {
    #[cfg(cfail1)]
    use super::c_i32 as c_int;
    #[cfg(not(cfail1))]
    use super::c_i64 as c_int;

    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
    #[rustc_clean(cfg = "cfail3")]
    extern "C" {
        pub fn indirectly_change_parameter_type(c: c_int);
    }
}

// Indirectly change return type --------------------------------------------
mod indirectly_change_return_type {
    #[cfg(cfail1)]
    use super::c_i32 as c_int;
    #[cfg(not(cfail1))]
    use super::c_i64 as c_int;

    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
    #[rustc_clean(cfg = "cfail3")]
    extern "C" {
        pub fn indirectly_change_return_type() -> c_int;
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..100 {
            env.str_def("hello", Expr::Str(StrNode::new("world")));
            let val = env.str_lookup("hello");
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<commit_msg>fix bench<commit_after>use std::collections::HashMap;
use std::cell::RefCell;
use std::rc::Rc;
use ast::*;
use test::Bencher;

#[derive(Clone, PartialEq)]
pub struct Env {
    pub table: HashMap<String, Expr>,
    pub parent: Option<Rc<RefCell<Env>>>
}

#[allow(unreachable_code)]
#[allow(dead_code)]
impl Env {
    pub fn new() -> Env {
        let mut res = Env {
            table: HashMap::new(),
            parent: None
        };
        res.setup();
        res
    }

    pub fn def_var(&mut self, var: String, val: Expr) {
        self.add_binding(var, val);
    }

    pub fn str_def(&mut self, var: &str, val: Expr) {
        self.add_binding(var.to_string(), val);
    }

    pub fn add_binding(&mut self, var: String, val: Expr) {
        self.table.insert(var, val);
    }

    pub fn lookup(&self, var: String) -> Option<Expr> {
        match self.table.get(&var) {
            Some(val) => return Some(val.clone()),
            _ => {}
        }
        match self.parent.clone() {
            Some(p) =>
                return p.borrow().lookup(var),
            _ => {
                return None;
            }
        };
    }

    pub fn str_lookup(&self, var: &str) -> Option<Expr> {
        self.lookup(var.to_string())
    }

    pub fn parent(&self) ->  Option<Rc<RefCell<Env>>> {
        match self.parent.clone() {
            Some(p) => return Some(p.clone()),
            _ => { return None; }
        }
    }

    pub fn extend(&mut self, vars: Expr, vals: Expr) -> Rc<RefCell<Env>> {
        let mut _vars = vars;
        let mut _vals = vals;
        let mut res = Env {
            table: HashMap::new(),
            parent: Some(Rc::new(RefCell::new(self.clone())))
        };
        loop {
            if _vars.is_last() { break; }
            res.add_binding(_vars.car().as_str(), _vals.car());
            _vars = _vars.cdr();
            _vals = _vals.cdr();
        }
        res.add_binding(_vars.car().as_str(), _vals.car());
        return Rc::new(RefCell::new(res));
    }

    fn setup(&mut self) {
        macro_rules! def_proc {
            ($func_name:ident, $raw_func_name:ident) => (
                fn $func_name(args: Expr) -> Expr {
                    Expr::Bool(BoolNode::new(args.car().$raw_func_name()))
                }
                )
        }

        macro_rules! add_proc {
            ($type_str:expr, $func_name:ident) => (
                self.def_var($type_str.to_string(),
                             Expr::Proc(ProcNode::new($func_name)))
                    )
        }

        def_proc!(is_null, is_empty);
        def_proc!(is_boolean, is_bool);
        def_proc!(is_symbol, is_symbol);
        def_proc!(is_string, is_string);
        def_proc!(is_pair, is_pair);
        def_proc!(is_char, is_char);
        def_proc!(is_int, is_int);

        add_proc!("null?", is_null);
        add_proc!("boolean?", is_boolean);
        add_proc!("symbol?", is_symbol);
        add_proc!("string?", is_string);
        add_proc!("char?", is_char);
        add_proc!("integer?", is_int);
        add_proc!("+", add);
        add_proc!("-", sub);
        add_proc!("*", mul);
        add_proc!("/", div);
        add_proc!("eq?", eq);
        add_proc!("=", eq);
        add_proc!("<", less);
        add_proc!(">", large);
        add_proc!("pair?", is_pair);
        add_proc!("car", car);
        add_proc!("cdr", cdr);
        add_proc!("cons", cons);
    }
}

fn add(args: Expr) -> Expr {
    let mut res = 0is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res += exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn sub(args: Expr) -> Expr {
    let mut res = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        res -= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn mul(args: Expr) -> Expr {
    let mut res = 1is;
    let mut exps = args;
    loop {
        if exps.is_empty() { break; }
        res *= exps.car().as_int();
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn div(args: Expr) -> Expr {
    let mut exps = args;
    let mut res = exps.car().as_int();
    exps = exps.cdr();
    loop {
        if exps.is_empty() { break; }
        let nxt = exps.car().as_int();
        if nxt == 0 {
            return Expr::Symbol(SymbolNode::new("Fail"));
        }
        res /= nxt;
        exps = exps.cdr();
    }
    Expr::Int(IntNode::new(res))
}

fn cons(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Pair(PairNode::new(obj1, Expr::Pair(PairNode::new(obj2, Expr::Nil))))
}

fn eq(args: Expr) -> Expr {
    let obj1 = args.car();
    let obj2 = args.c("da");
    Expr::Bool(BoolNode::new(obj1 == obj2))
}

fn less(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val >= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

fn car(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("aa")
}

fn cdr(args: Expr) -> Expr {
    assert!(args.car().is_pair());
    args.c("ad")
}

fn large(args: Expr) -> Expr {
    let val = args.car().as_int();
    let mut exps = args.cdr();
    loop {
        if exps.is_empty() { break; }
        if val <= exps.car().as_int() {
            return Expr::Bool(BoolNode::new(false));
        }
        exps = exps.cdr();
    }
    Expr::Bool(BoolNode::new(true))
}

#[test]
fn test_env() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let val = env.str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    env.str_def("1", Expr::Int(IntNode::new(1)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 1);

    env.str_def("1", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("1");
    assert!(val.unwrap().as_int() == 2);

    env.str_def("sym", Expr::Int(IntNode::new(2)));
    let val = env.str_lookup("sym");
    assert!(val.unwrap().as_int() == 2);

    let val = env.str_lookup("null?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("char?");
    assert!(val.unwrap().is_proc());
    let val = env.str_lookup("integer?");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup(">");
    assert!(val.unwrap().is_proc());

    let val = env.str_lookup("<");
    assert!(val.unwrap().is_proc());

}

#[test]
fn test_env_extend() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var");
    assert!(val.unwrap().as_str() == "val");

    let val = extend_env.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var_x")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val_x")), Expr::Nil));

    let extend_env = extend_env.clone().borrow_mut().extend(vars, vals);
    let val = extend_env.clone().borrow_mut().str_lookup("var_x");
    assert!(val.unwrap().as_str() == "val_x");

    extend_env.clone().borrow_mut().str_def("1", Expr::Str(StrNode::new("1")));

    let val = extend_env.clone().borrow_mut().str_lookup("1");
    assert!(val.unwrap().as_str() == "1");
}

#[test]
fn test_env_parent() {
    let mut env = Env::new();
    env.str_def("hello", Expr::Str(StrNode::new("world")));

    let vars = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("var")), Expr::Nil));
    let vals = Expr::Pair(PairNode::new( Expr::Str(StrNode::new("val")), Expr::Nil));

    let extend_env = env.extend(vars, vals);
    let parent = extend_env.clone().borrow_mut().parent().unwrap();
    let val = parent.clone().borrow_mut().str_lookup("hello");
    assert!(val.unwrap().as_str() == "world");
}

#[bench]
fn env_bench(b: &mut Bencher) {
    fn test_env() {
        let mut env = Env::new();
        for i in 1..1000 {
            let key = i.to_string();
            env.def_var(key.clone(), Expr::Str(StrNode::new("world")));
            let val = env.lookup(key);
            assert!(val.unwrap().as_str() == "world");
        }
    }

    b.iter(|| test_env());
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::io::stdin;
use std::fs::OpenOptions;
use std::result::Result as RResult;
use std::io::Read;
use std::ops::DerefMut;

use clap::ArgMatches;
use toml::Value;

use libimagrt::runtime::Runtime;
use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error_exit;
use libimagutil::debug_result::*;

use error::StoreError;
use error::StoreErrorKind;
use error::ResultExt;
use util::build_toml_header;

type Result<T> = RResult<T, StoreError>;

pub fn create(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("create").unwrap();
    debug!("Found 'create' subcommand...");

    // unwrap is safe as value is required
    let path  = scmd.value_of("path").unwrap();
    let path  = PathBuf::from(path);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).unwrap_or_else(|e| trace_error_exit(&e, 1));

    debug!("path = {:?}", path);

    if scmd.subcommand_matches("entry").is_some() {
        debug!("Creating entry from CLI specification");
        create_from_cli_spec(rt, scmd, &path)
            .or_else(|_| create_from_source(rt, scmd, &path))
            .or_else(|_| create_with_content_and_header(rt,
                                                        &path,
                                                        String::new(),
                                                        Entry::default_header()))
    } else {
        debug!("Creating entry");
        create_with_content_and_header(rt, &path, String::new(),
            Entry::default_header())
    }
    .unwrap_or_else(|e| {
        error!("Error building Entry");
        trace_error_exit(&e, 1);
    })
}

fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
    let content = matches.subcommand_matches("entry")
        .map_or_else(|| {
            debug!("Didn't find entry subcommand, getting raw content");
            matches.value_of("from-raw")
                .map_or_else(String::new, string_from_raw_src)
        }, |entry_subcommand| {
            debug!("Found entry subcommand, parsing content");
            entry_subcommand
                .value_of("content")
                .map_or_else(|| {
                    entry_subcommand.value_of("content-from")
                        .map_or_else(String::new, string_from_raw_src)
                }, String::from)
        });
    debug!("Got content with len = {}", content.len());

    let header = matches.subcommand_matches("entry")
        .map_or_else(|| Entry::default_header(),
            |entry_matches| build_toml_header(entry_matches, Entry::default_header()));

    create_with_content_and_header(rt, path, content, header)
}

fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
    let content = matches
        .value_of("from-raw")
        .ok_or(StoreError::from_kind(StoreErrorKind::NoCommandlineCall))
        .map(string_from_raw_src);

    if content.is_err() {
        return content.map(|_| ());
    }
    let content = content.unwrap();
    debug!("Content with len = {}", content.len());

    Entry::from_str(path.clone(), &content[..])
        .map_dbg_err(|e| format!("Error building entry: {:?}", e))
        .and_then(|new_e| {
            let r = rt.store()
                .create(path.clone())
                .map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
                .map(|mut old_e| {
                    *old_e.deref_mut() = new_e;
                });

            debug!("Entry build");
            r
        })
        .map_dbg_err(|e| format!("Error storing entry: {:?}", e))
        .chain_err(|| StoreErrorKind::BackendError)
}

fn create_with_content_and_header(rt: &Runtime,
                                  path: &StoreId,
                                  content: String,
                                  header: Value) -> Result<()>
{
    debug!("Creating entry with content at {:?}", path);
    rt.store()
        .create(path.clone())
        .map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
        .map(|mut element| {
            {
                let e_content = element.get_content_mut();
                *e_content = content;
                debug!("New content set");
            }
            {
                let e_header  = element.get_header_mut();
                *e_header = header;
                debug!("New header set");
            }
        })
        .chain_err(|| StoreErrorKind::BackendError)
}

fn string_from_raw_src(raw_src: &str) -> String {
    let mut content = String::new();
    if raw_src == "-" {
        debug!("Reading entry from stdin");
        let res = stdin().read_to_string(&mut content);
        debug!("Read {:?} bytes", res);
    } else {
        debug!("Reading entry from file at {:?}", raw_src);
        let _ = OpenOptions::new()
            .read(true)
            .write(false)
            .create(false)
            .open(raw_src)
            .and_then(|mut f| f.read_to_string(&mut content));
    }
    content
}

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

    use std::path::PathBuf;
    use toml_query::read::TomlValueReadExt;
    use toml::Value;

    make_mock_app! {
        app "imag-link";
        modulename mock;
        version "0.4.0";
        with help "imag-link mocking app";
    }
    use self::mock::generate_test_runtime;

    #[test]
    fn test_create_simple() {
        let test_name = "test_create_simple";
        let rt = generate_test_runtime(vec!["create", "-p", "test_create_simple"]).unwrap();

        create(&rt);

        let e = rt.store().get(PathBuf::from(test_name));
        assert!(e.is_ok());
        let e = e.unwrap();
        assert!(e.is_some());
        let e = e.unwrap();

        let version = e.get_header().read("imag.version").map(Option::unwrap).unwrap();
        assert_eq!(Value::String(String::from("0.4.0")), *version);
    }

}

<commit_msg>Adapt cli-test for create()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::io::stdin;
use std::fs::OpenOptions;
use std::result::Result as RResult;
use std::io::Read;
use std::ops::DerefMut;

use clap::ArgMatches;
use toml::Value;

use libimagrt::runtime::Runtime;
use libimagstore::store::Entry;
use libimagstore::storeid::StoreId;
use libimagerror::trace::trace_error_exit;
use libimagutil::debug_result::*;

use error::StoreError;
use error::StoreErrorKind;
use error::ResultExt;
use util::build_toml_header;

type Result<T> = RResult<T, StoreError>;

pub fn create(rt: &Runtime) {
    let scmd = rt.cli().subcommand_matches("create").unwrap();
    debug!("Found 'create' subcommand...");

    // unwrap is safe as value is required
    let path  = scmd.value_of("path").unwrap();
    let path  = PathBuf::from(path);
    let store = Some(rt.store().path().clone());
    let path  = StoreId::new(store, path).unwrap_or_else(|e| trace_error_exit(&e, 1));

    debug!("path = {:?}", path);

    if scmd.subcommand_matches("entry").is_some() {
        debug!("Creating entry from CLI specification");
        create_from_cli_spec(rt, scmd, &path)
            .or_else(|_| create_from_source(rt, scmd, &path))
            .or_else(|_| create_with_content_and_header(rt,
                                                        &path,
                                                        String::new(),
                                                        Entry::default_header()))
    } else {
        debug!("Creating entry");
        create_with_content_and_header(rt, &path, String::new(),
            Entry::default_header())
    }
    .unwrap_or_else(|e| {
        error!("Error building Entry");
        trace_error_exit(&e, 1);
    })
}

fn create_from_cli_spec(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
    let content = matches.subcommand_matches("entry")
        .map_or_else(|| {
            debug!("Didn't find entry subcommand, getting raw content");
            matches.value_of("from-raw")
                .map_or_else(String::new, string_from_raw_src)
        }, |entry_subcommand| {
            debug!("Found entry subcommand, parsing content");
            entry_subcommand
                .value_of("content")
                .map_or_else(|| {
                    entry_subcommand.value_of("content-from")
                        .map_or_else(String::new, string_from_raw_src)
                }, String::from)
        });
    debug!("Got content with len = {}", content.len());

    let header = matches.subcommand_matches("entry")
        .map_or_else(|| Entry::default_header(),
            |entry_matches| build_toml_header(entry_matches, Entry::default_header()));

    create_with_content_and_header(rt, path, content, header)
}

fn create_from_source(rt: &Runtime, matches: &ArgMatches, path: &StoreId) -> Result<()> {
    let content = matches
        .value_of("from-raw")
        .ok_or(StoreError::from_kind(StoreErrorKind::NoCommandlineCall))
        .map(string_from_raw_src);

    if content.is_err() {
        return content.map(|_| ());
    }
    let content = content.unwrap();
    debug!("Content with len = {}", content.len());

    Entry::from_str(path.clone(), &content[..])
        .map_dbg_err(|e| format!("Error building entry: {:?}", e))
        .and_then(|new_e| {
            let r = rt.store()
                .create(path.clone())
                .map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
                .map(|mut old_e| {
                    *old_e.deref_mut() = new_e;
                });

            debug!("Entry build");
            r
        })
        .map_dbg_err(|e| format!("Error storing entry: {:?}", e))
        .chain_err(|| StoreErrorKind::BackendError)
}

fn create_with_content_and_header(rt: &Runtime,
                                  path: &StoreId,
                                  content: String,
                                  header: Value) -> Result<()>
{
    debug!("Creating entry with content at {:?}", path);
    rt.store()
        .create(path.clone())
        .map_dbg_err(|e| format!("Error in Store::create(): {:?}", e))
        .map(|mut element| {
            {
                let e_content = element.get_content_mut();
                *e_content = content;
                debug!("New content set");
            }
            {
                let e_header  = element.get_header_mut();
                *e_header = header;
                debug!("New header set");
            }
        })
        .chain_err(|| StoreErrorKind::BackendError)
}

fn string_from_raw_src(raw_src: &str) -> String {
    let mut content = String::new();
    if raw_src == "-" {
        debug!("Reading entry from stdin");
        let res = stdin().read_to_string(&mut content);
        debug!("Read {:?} bytes", res);
    } else {
        debug!("Reading entry from file at {:?}", raw_src);
        let _ = OpenOptions::new()
            .read(true)
            .write(false)
            .create(false)
            .open(raw_src)
            .and_then(|mut f| f.read_to_string(&mut content));
    }
    content
}

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

    use std::path::PathBuf;
    use toml_query::read::TomlValueReadExt;
    use toml::Value;

    make_mock_app! {
        app "imag-store";
        modulename mock;
        version "0.4.0";
        with help "imag-store mocking app";
    }
    use self::mock::generate_test_runtime;

    #[test]
    fn test_create_simple() {
        let test_name = "test_create_simple";
        let rt = generate_test_runtime(vec!["create", "test_create_simple"]).unwrap();

        create(&rt);

        let e = rt.store().get(PathBuf::from(test_name));
        assert!(e.is_ok());
        let e = e.unwrap();
        assert!(e.is_some());
        let e = e.unwrap();

        let version = e.get_header().read("imag.version").map(Option::unwrap).unwrap();
        assert_eq!(Value::String(String::from("0.4.0")), *version);
    }

}

<|endoftext|>


<commit_before>//! A very simple HTTP server which responds with the plain text "Hello, World!" to every request.

extern mod extra;
extern mod http;

use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use std::rt::io::Writer;
use extra::time;

use http::server::{Config, Server, ServerUtil, Request, ResponseWriter};
use http::headers::content_type::MediaType;

#[deriving(Clone)]
struct HelloWorldServer;

impl Server for HelloWorldServer {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
    }

    fn handle_request(&self, _r: &Request, w: &mut ResponseWriter) {
        w.headers.date = Some(time::now_utc());
        w.headers.content_length = Some(15);
        w.headers.content_type = Some(MediaType {
            type_: ~"text",
            subtype: ~"plain",
            parameters: ~[(~"charset", ~"UTF-8")]
        });
        w.headers.server = Some(~"Example");

        w.write(bytes!("Hello, World!"));
    }
}

fn main() {
    HelloWorldServer.serve_forever();
}
<commit_msg>Fix up hello_world example's Content-Length.<commit_after>//! A very simple HTTP server which responds with the plain text "Hello, World!" to every request.

extern mod extra;
extern mod http;

use std::rt::io::net::ip::{SocketAddr, Ipv4Addr};
use std::rt::io::Writer;
use extra::time;

use http::server::{Config, Server, ServerUtil, Request, ResponseWriter};
use http::headers::content_type::MediaType;

#[deriving(Clone)]
struct HelloWorldServer;

impl Server for HelloWorldServer {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
    }

    fn handle_request(&self, _r: &Request, w: &mut ResponseWriter) {
        w.headers.date = Some(time::now_utc());
        w.headers.content_length = Some(14);
        w.headers.content_type = Some(MediaType {
            type_: ~"text",
            subtype: ~"plain",
            parameters: ~[(~"charset", ~"UTF-8")]
        });
        w.headers.server = Some(~"Example");

        w.write(bytes!("Hello, World!\n"));
    }
}

fn main() {
    HelloWorldServer.serve_forever();
}
<|endoftext|>


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

use quote::Tokens;
use walkdir::WalkDir;
use cfg::CargonautsConfig;

const FLAG: &'static str = "used_cargonauts_asset_pipeline";

pub fn assets(cfg: Option<&CargonautsConfig>) -> Tokens {
    let dir = {
        // First, check if they used an asset pipeline
        let used_asset_pipeline = env::args().find(|arg| arg.starts_with(FLAG));
        if let Some(arg) = used_asset_pipeline {
            // Check if they specified an unusual build directory
            let arg =  arg.trim_left_matches(FLAG);
            if arg.len() > 2 && arg.starts_with('[') && arg.ends_with(']') {
                let root: PathBuf = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set").into();
                let range = 1..(arg.len() - 1);
                root.join(&arg[range])
            } else {
                // If they didn't, assets are in OUT_DIR/cargonauts/assets
                let out_dir: PathBuf = env::var("OUT_DIR").expect("OUT_DIR not set").into();
                out_dir.join("cargonauts/assets")
            }
        } else {
            // If they didn't use a pipeline, find their normal assets folder
            let root: PathBuf = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set").into();
            root.join(cfg.and_then(|cfg| cfg.assets()).unwrap_or(Path::new("src/assets")))
        }
    };

    let assets = WalkDir::new(&dir).into_iter().filter_map(|entry| {
        let entry = if let Ok(entry) = entry { entry } else { return None };
        if entry.file_type().is_file() {
            let file_path = entry.path().to_string_lossy();
            let relative_path = entry.path().strip_prefix(&dir).unwrap().to_string_lossy();
            Some(quote!((#relative_path, include_bytes!(#file_path) as &[u8])))
        } else { None }
    }).collect::<Vec<_>>();

    quote! {
        vec!#assets.into_iter().collect();
    }
}
<commit_msg>Support _index assets.<commit_after>use std::env;
use std::path::{Path, PathBuf};

use quote::Tokens;
use walkdir::WalkDir;
use cfg::CargonautsConfig;

const FLAG: &'static str = "used_cargonauts_asset_pipeline";

pub fn assets(cfg: Option<&CargonautsConfig>) -> Tokens {
    let dir = {
        // First, check if they used an asset pipeline
        let used_asset_pipeline = env::args().find(|arg| arg.starts_with(FLAG));
        if let Some(arg) = used_asset_pipeline {
            // Check if they specified an unusual build directory
            let arg =  arg.trim_left_matches(FLAG);
            if arg.len() > 2 && arg.starts_with('[') && arg.ends_with(']') {
                let root: PathBuf = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set").into();
                let range = 1..(arg.len() - 1);
                root.join(&arg[range])
            } else {
                // If they didn't, assets are in OUT_DIR/cargonauts/assets
                let out_dir: PathBuf = env::var("OUT_DIR").expect("OUT_DIR not set").into();
                out_dir.join("cargonauts/assets")
            }
        } else {
            // If they didn't use a pipeline, find their normal assets folder
            let root: PathBuf = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set").into();
            root.join(cfg.and_then(|cfg| cfg.assets()).unwrap_or(Path::new("src/assets")))
        }
    };

    let assets = WalkDir::new(&dir).into_iter().filter_map(|entry| entry.ok().and_then(|entry| {
        if entry.file_type().is_file() {
            let path = entry.path();
            let file_path = path.to_string_lossy();
            let url_path = if entry.file_name().to_string_lossy().starts_with("_index") {
                path.strip_prefix(&dir).unwrap().parent().unwrap().to_string_lossy()
            } else {
                path.strip_prefix(&dir).unwrap().to_string_lossy()
            };
            Some(quote!((#url_path, include_bytes!(#file_path) as &[u8])))
        } else { None }
    })).collect::<Vec<_>>();

    quote! {
        vec!#assets.into_iter().collect();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

#[allow(non_camel_case_types)]
pub type key_serial_t = libc::int32_t;

pub const KEY_SPEC_THREAD_KEYRING:          key_serial_t = -1;
pub const KEY_SPEC_PROCESS_KEYRING:         key_serial_t = -2;
pub const KEY_SPEC_SESSION_KEYRING:         key_serial_t = -3;
pub const KEY_SPEC_USER_KEYRING:            key_serial_t = -4;
pub const KEY_SPEC_USER_SESSION_KEYRING:    key_serial_t = -5;
pub const KEY_SPEC_GROUP_KEYRING:           key_serial_t = -6;
pub const KEY_SPEC_REQKEY_AUTH_KEY:         key_serial_t = -7;

pub const KEY_REQKEY_DEFL_NO_CHANGE:            key_serial_t = -1;
pub const KEY_REQKEY_DEFL_DEFAULT:              key_serial_t = 0;
pub const KEY_REQKEY_DEFL_THREAD_KEYRING:       key_serial_t = 1;
pub const KEY_REQKEY_DEFL_PROCESS_KEYRING:      key_serial_t = 2;
pub const KEY_REQKEY_DEFL_SESSION_KEYRING:      key_serial_t = 3;
pub const KEY_REQKEY_DEFL_USER_KEYRING:         key_serial_t = 4;
pub const KEY_REQKEY_DEFL_USER_SESSION_KEYRING: key_serial_t = 5;
pub const KEY_REQKEY_DEFL_GROUP_KEYRING:        key_serial_t = 6;

#[allow(non_camel_case_types)]
pub type key_perm_t = libc::uint32_t;

pub const KEY_POS_VIEW:    key_perm_t = 0x01000000;     /* possessor can view a key's attributes */
pub const KEY_POS_READ:    key_perm_t = 0x02000000;     /* possessor can read key payload / view keyring */
pub const KEY_POS_WRITE:   key_perm_t = 0x04000000;     /* possessor can update key payload / add link to keyring */
pub const KEY_POS_SEARCH:  key_perm_t = 0x08000000;     /* possessor can find a key in search / search a keyring */
pub const KEY_POS_LINK:    key_perm_t = 0x10000000;     /* possessor can create a link to a key/keyring */
pub const KEY_POS_SETATTR: key_perm_t = 0x20000000;     /* possessor can set key attributes */
pub const KEY_POS_ALL:     key_perm_t = 0x3f000000;

pub const KEY_USR_VIEW:    key_perm_t = 0x00010000;     /* user permissions... */
pub const KEY_USR_READ:    key_perm_t = 0x00020000;
pub const KEY_USR_WRITE:   key_perm_t = 0x00040000;
pub const KEY_USR_SEARCH:  key_perm_t = 0x00080000;
pub const KEY_USR_LINK:    key_perm_t = 0x00100000;
pub const KEY_USR_SETATTR: key_perm_t = 0x00200000;
pub const KEY_USR_ALL:     key_perm_t = 0x003f0000;

pub const KEY_GRP_VIEW:    key_perm_t = 0x00000100;     /* group permissions... */
pub const KEY_GRP_READ:    key_perm_t = 0x00000200;
pub const KEY_GRP_WRITE:   key_perm_t = 0x00000400;
pub const KEY_GRP_SEARCH:  key_perm_t = 0x00000800;
pub const KEY_GRP_LINK:    key_perm_t = 0x00001000;
pub const KEY_GRP_SETATTR: key_perm_t = 0x00002000;
pub const KEY_GRP_ALL:     key_perm_t = 0x00003f00;

pub const KEY_OTH_VIEW:    key_perm_t = 0x00000001;     /* third party permissions... */
pub const KEY_OTH_READ:    key_perm_t = 0x00000002;
pub const KEY_OTH_WRITE:   key_perm_t = 0x00000004;
pub const KEY_OTH_SEARCH:  key_perm_t = 0x00000008;
pub const KEY_OTH_LINK:    key_perm_t = 0x00000010;
pub const KEY_OTH_SETATTR: key_perm_t = 0x00000020;
pub const KEY_OTH_ALL:     key_perm_t = 0x0000003f;

#[link(name = "keyutils")]
extern {
    pub fn add_key(
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        payload:        *const libc::c_void,
        plen:           libc::size_t,
        keyring:        key_serial_t)
        -> key_serial_t;
    pub fn request_key(
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        callout_info:   *const libc::c_char,
        keyring:        key_serial_t)
        -> key_serial_t;

    pub fn keyctl_get_keyring_ID(
        id:     key_serial_t,
        create: libc::c_int)
        -> key_serial_t;
    pub fn keyctl_join_session_keyring(
        name:   *const libc::c_char)
        -> key_serial_t;
    pub fn keyctl_update(
        id:         key_serial_t,
        payload:    *const libc::c_void,
        plen:       libc::size_t)
        -> libc::c_long;
    pub fn keyctl_revoke(
        id: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_chown(
        id:     key_serial_t,
        uid:    libc::uid_t,
        gid:    libc::gid_t)
        -> libc::c_long;
    pub fn keyctl_setperm(
        id:     key_serial_t,
        perm:   key_perm_t)
        -> libc::c_long;
    pub fn keyctl_describe(
        id:     key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    pub fn keyctl_clear(
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_link(
        id:     key_serial_t,
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_unlink(
        id:     key_serial_t,
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_search(
        ringid:         key_serial_t,
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        destringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_read(
        id:     key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    pub fn keyctl_instantiate(
        id:         key_serial_t,
        payload:    *const libc::c_void,
        plen:       libc::size_t,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_negate(
        id:         key_serial_t,
        timeout:    libc::c_uint,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_set_reqkey_keyring(
        reqkey_defl:    libc::c_int)
        -> libc::c_long;
    pub fn keyctl_set_timeout(
        key:        key_serial_t,
        timeout:    libc::c_uint)
        -> libc::c_long;
    pub fn keyctl_assume_authority(
        key:    key_serial_t)
        -> libc::c_long;
    pub fn keyctl_get_security(
        key:    key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    //pub fn keyctl_session_to_parent()
    //    -> libc::c_long;
    pub fn keyctl_reject(
        id:         key_serial_t,
        timeout:    libc::c_uint,
        error:      libc::c_uint,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_invalidate(
        id: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_get_persistent(
        uid:    libc::uid_t,
        id:     key_serial_t)
        -> libc::c_long;
}
<commit_msg>rustfmt: use `extern "C"`<commit_after>extern crate libc;

#[allow(non_camel_case_types)]
pub type key_serial_t = libc::int32_t;

pub const KEY_SPEC_THREAD_KEYRING:          key_serial_t = -1;
pub const KEY_SPEC_PROCESS_KEYRING:         key_serial_t = -2;
pub const KEY_SPEC_SESSION_KEYRING:         key_serial_t = -3;
pub const KEY_SPEC_USER_KEYRING:            key_serial_t = -4;
pub const KEY_SPEC_USER_SESSION_KEYRING:    key_serial_t = -5;
pub const KEY_SPEC_GROUP_KEYRING:           key_serial_t = -6;
pub const KEY_SPEC_REQKEY_AUTH_KEY:         key_serial_t = -7;

pub const KEY_REQKEY_DEFL_NO_CHANGE:            key_serial_t = -1;
pub const KEY_REQKEY_DEFL_DEFAULT:              key_serial_t = 0;
pub const KEY_REQKEY_DEFL_THREAD_KEYRING:       key_serial_t = 1;
pub const KEY_REQKEY_DEFL_PROCESS_KEYRING:      key_serial_t = 2;
pub const KEY_REQKEY_DEFL_SESSION_KEYRING:      key_serial_t = 3;
pub const KEY_REQKEY_DEFL_USER_KEYRING:         key_serial_t = 4;
pub const KEY_REQKEY_DEFL_USER_SESSION_KEYRING: key_serial_t = 5;
pub const KEY_REQKEY_DEFL_GROUP_KEYRING:        key_serial_t = 6;

#[allow(non_camel_case_types)]
pub type key_perm_t = libc::uint32_t;

pub const KEY_POS_VIEW:    key_perm_t = 0x01000000;     /* possessor can view a key's attributes */
pub const KEY_POS_READ:    key_perm_t = 0x02000000;     /* possessor can read key payload / view keyring */
pub const KEY_POS_WRITE:   key_perm_t = 0x04000000;     /* possessor can update key payload / add link to keyring */
pub const KEY_POS_SEARCH:  key_perm_t = 0x08000000;     /* possessor can find a key in search / search a keyring */
pub const KEY_POS_LINK:    key_perm_t = 0x10000000;     /* possessor can create a link to a key/keyring */
pub const KEY_POS_SETATTR: key_perm_t = 0x20000000;     /* possessor can set key attributes */
pub const KEY_POS_ALL:     key_perm_t = 0x3f000000;

pub const KEY_USR_VIEW:    key_perm_t = 0x00010000;     /* user permissions... */
pub const KEY_USR_READ:    key_perm_t = 0x00020000;
pub const KEY_USR_WRITE:   key_perm_t = 0x00040000;
pub const KEY_USR_SEARCH:  key_perm_t = 0x00080000;
pub const KEY_USR_LINK:    key_perm_t = 0x00100000;
pub const KEY_USR_SETATTR: key_perm_t = 0x00200000;
pub const KEY_USR_ALL:     key_perm_t = 0x003f0000;

pub const KEY_GRP_VIEW:    key_perm_t = 0x00000100;     /* group permissions... */
pub const KEY_GRP_READ:    key_perm_t = 0x00000200;
pub const KEY_GRP_WRITE:   key_perm_t = 0x00000400;
pub const KEY_GRP_SEARCH:  key_perm_t = 0x00000800;
pub const KEY_GRP_LINK:    key_perm_t = 0x00001000;
pub const KEY_GRP_SETATTR: key_perm_t = 0x00002000;
pub const KEY_GRP_ALL:     key_perm_t = 0x00003f00;

pub const KEY_OTH_VIEW:    key_perm_t = 0x00000001;     /* third party permissions... */
pub const KEY_OTH_READ:    key_perm_t = 0x00000002;
pub const KEY_OTH_WRITE:   key_perm_t = 0x00000004;
pub const KEY_OTH_SEARCH:  key_perm_t = 0x00000008;
pub const KEY_OTH_LINK:    key_perm_t = 0x00000010;
pub const KEY_OTH_SETATTR: key_perm_t = 0x00000020;
pub const KEY_OTH_ALL:     key_perm_t = 0x0000003f;

#[link(name = "keyutils")]
extern "C" {
    pub fn add_key(
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        payload:        *const libc::c_void,
        plen:           libc::size_t,
        keyring:        key_serial_t)
        -> key_serial_t;
    pub fn request_key(
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        callout_info:   *const libc::c_char,
        keyring:        key_serial_t)
        -> key_serial_t;

    pub fn keyctl_get_keyring_ID(
        id:     key_serial_t,
        create: libc::c_int)
        -> key_serial_t;
    pub fn keyctl_join_session_keyring(
        name:   *const libc::c_char)
        -> key_serial_t;
    pub fn keyctl_update(
        id:         key_serial_t,
        payload:    *const libc::c_void,
        plen:       libc::size_t)
        -> libc::c_long;
    pub fn keyctl_revoke(
        id: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_chown(
        id:     key_serial_t,
        uid:    libc::uid_t,
        gid:    libc::gid_t)
        -> libc::c_long;
    pub fn keyctl_setperm(
        id:     key_serial_t,
        perm:   key_perm_t)
        -> libc::c_long;
    pub fn keyctl_describe(
        id:     key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    pub fn keyctl_clear(
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_link(
        id:     key_serial_t,
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_unlink(
        id:     key_serial_t,
        ringid: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_search(
        ringid:         key_serial_t,
        type_:          *const libc::c_char,
        description:    *const libc::c_char,
        destringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_read(
        id:     key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    pub fn keyctl_instantiate(
        id:         key_serial_t,
        payload:    *const libc::c_void,
        plen:       libc::size_t,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_negate(
        id:         key_serial_t,
        timeout:    libc::c_uint,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_set_reqkey_keyring(
        reqkey_defl:    libc::c_int)
        -> libc::c_long;
    pub fn keyctl_set_timeout(
        key:        key_serial_t,
        timeout:    libc::c_uint)
        -> libc::c_long;
    pub fn keyctl_assume_authority(
        key:    key_serial_t)
        -> libc::c_long;
    pub fn keyctl_get_security(
        key:    key_serial_t,
        buffer: *mut libc::c_char,
        buflen: libc::size_t)
        -> libc::c_long;
    //pub fn keyctl_session_to_parent()
    //    -> libc::c_long;
    pub fn keyctl_reject(
        id:         key_serial_t,
        timeout:    libc::c_uint,
        error:      libc::c_uint,
        ringid:     key_serial_t)
        -> libc::c_long;
    pub fn keyctl_invalidate(
        id: key_serial_t)
        -> libc::c_long;
    pub fn keyctl_get_persistent(
        uid:    libc::uid_t,
        id:     key_serial_t)
        -> libc::c_long;
}
<|endoftext|>


<commit_before>use libc;

pub fn alloc(sz: usize) -> *mut libc::c_void {
    unsafe {
        let ptr = libc::malloc(sz as libc::size_t);
        if ptr.is_null() {
            panic!("malloc failed!");
        }

        ptr
    }
}
<commit_msg>Eh, we don't need ffi.rs just yet<commit_after><|endoftext|>


<commit_before>use crate::error::Error::{self, IOError, ModuleSignatureError};
use crate::module::{SerializedModule, LUCET_MODULE_SYM};
use crate::module_data::MODULE_DATA_SYM;
use crate::ModuleData;
use byteorder::{ByteOrder, LittleEndian};
use memoffset::offset_of;
pub use minisign::{PublicKey, SecretKey};
use minisign::{SignatureBones, SignatureBox};
use object::*;
use std::fs::{File, OpenOptions};
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
use std::path::Path;

pub struct ModuleSignature;

impl ModuleSignature {
    pub fn verify<P: AsRef<Path>>(
        so_path: P,
        pk: &PublicKey,
        module_data: &ModuleData,
    ) -> Result<(), Error> {
        let signature_box: SignatureBox =
            SignatureBones::from_bytes(&module_data.get_module_signature())
                .map_err(|e| ModuleSignatureError(e))?
                .into();

        let mut raw_module_and_data =
            RawModuleAndData::from_file(&so_path).map_err(|e| IOError(e))?;
        let cleared_module_data_bin =
            ModuleData::clear_module_signature(raw_module_and_data.module_data_bin())?;
        raw_module_and_data.patch_module_data(&cleared_module_data_bin);

        minisign::verify(
            &pk,
            &signature_box,
            Cursor::new(&raw_module_and_data.obj_bin),
            true,
            false,
        )
        .map_err(|e| ModuleSignatureError(e))
    }

    pub fn sign<P: AsRef<Path>>(path: P, sk: &SecretKey) -> Result<(), Error> {
        let raw_module_and_data = RawModuleAndData::from_file(&path).map_err(|e| IOError(e))?;
        let signature_box = minisign::sign(
            None,
            sk,
            Cursor::new(&raw_module_and_data.obj_bin),
            true,
            None,
            None,
        )
        .map_err(|e| ModuleSignatureError(e))?;
        let signature_bones: SignatureBones = signature_box.into();
        let patched_module_data_bin = ModuleData::patch_module_signature(
            raw_module_and_data.module_data_bin(),
            &signature_bones.to_bytes(),
        )?;
        raw_module_and_data
            .write_patched_module_data(&path, &patched_module_data_bin)
            .map_err(|e| IOError(e))?;
        Ok(())
    }
}

#[allow(dead_code)]
struct SymbolData {
    offset: usize,
    len: usize,
}

struct RawModuleAndData {
    pub obj_bin: Vec<u8>,
    pub module_data_offset: usize,
    pub module_data_len: usize,
}

impl RawModuleAndData {
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
        let mut obj_bin: Vec<u8> = Vec::new();
        File::open(&path)?.read_to_end(&mut obj_bin)?;

        let native_data_symbol_data =
            Self::symbol_data(&obj_bin, LUCET_MODULE_SYM, true)?.ok_or(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("`{}` symbol not present", LUCET_MODULE_SYM),
            ))?;

        // While `module_data` is the first field of the `SerializedModule` that `lucet_module` points
        // to, it is a virtual address, not a file offset. The translation is somewhat tricky at
        // the moment, so just look at the corresponding `lucet_module_data` symbol for now.
        let module_data_symbol_data =
            Self::symbol_data(&obj_bin, MODULE_DATA_SYM, true)?.ok_or(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("`{}` symbol not present", MODULE_DATA_SYM),
            ))?;

        let module_data_len = LittleEndian::read_u64(
            &obj_bin[(native_data_symbol_data.offset
                + offset_of!(SerializedModule, module_data_len))..],
        ) as usize;

        Ok(RawModuleAndData {
            obj_bin,
            module_data_offset: module_data_symbol_data.offset,
            module_data_len: module_data_len,
        })
    }

    pub fn module_data_bin(&self) -> &[u8] {
        &self.obj_bin[self.module_data_offset as usize
            ..self.module_data_offset as usize + self.module_data_len]
    }

    pub fn module_data_bin_mut(&mut self) -> &mut [u8] {
        &mut self.obj_bin[self.module_data_offset as usize
            ..self.module_data_offset as usize + self.module_data_len]
    }

    pub fn patch_module_data(&mut self, module_data_bin: &[u8]) {
        self.module_data_bin_mut().copy_from_slice(&module_data_bin);
    }

    pub fn write_patched_module_data<P: AsRef<Path>>(
        &self,
        path: P,
        patched_module_data_bin: &[u8],
    ) -> Result<(), io::Error> {
        let mut fp = OpenOptions::new()
            .write(true)
            .create_new(false)
            .open(&path)?;
        fp.seek(SeekFrom::Start(self.module_data_offset as u64))?;
        fp.write_all(&patched_module_data_bin)?;
        Ok(())
    }

    // Retrieving the offset of a symbol is not supported by the object crate.
    // In Mach-O, actual file offsets are encoded, whereas Elf encodes virtual
    // addresses, requiring extra steps to retrieve the section, its base
    // address as well as the section offset.

    // Elf
    #[cfg(all(target_family = "unix", not(target_os = "macos")))]
    fn symbol_data(
        obj_bin: &[u8],
        symbol_name: &str,
        _mangle: bool,
    ) -> Result<Option<SymbolData>, io::Error> {
        let obj = object::ElfFile::parse(obj_bin)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
        let symbol_map = obj.symbol_map();
        for symbol in symbol_map.symbols() {
            let kind = symbol.kind();
            if kind != SymbolKind::Data {
                continue;
            }
            if symbol.name() != Some(symbol_name) {
                continue;
            }
            let section_index = match symbol.section_index() {
                Some(section_index) => section_index,
                None => continue,
            };
            let section = &obj.elf().section_headers[section_index.0];
            let offset = (symbol.address() - section.sh_addr + section.sh_offset) as usize;
            let len = symbol.size() as usize;
            return Ok(Some(SymbolData { offset, len }));
        }
        Ok(None)
    }

    // Mach-O
    #[cfg(target_os = "macos")]
    fn symbol_data(
        obj_bin: &[u8],
        symbol_name: &str,
        mangle: bool,
    ) -> Result<Option<SymbolData>, io::Error> {
        let obj = object::File::parse(obj_bin)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
        let symbol_map = obj.symbol_map();
        let mangled_symbol_name = format!("_{}", symbol_name);
        let symbol_name = if mangle {
            &mangled_symbol_name
        } else {
            symbol_name
        };
        for symbol in symbol_map.symbols() {
            let kind = symbol.kind();
            if kind != SymbolKind::Data && kind != SymbolKind::Unknown {
                continue;
            }
            if symbol.name() != Some(symbol_name) {
                continue;
            }
            let offset = symbol.address() as usize;
            let len = symbol.size() as usize;
            return Ok(Some(SymbolData { offset, len }));
        }
        Ok(None)
    }
}
<commit_msg>clean up symbol data code<commit_after>use crate::error::Error::{self, IOError, ModuleSignatureError};
use crate::module::{SerializedModule, LUCET_MODULE_SYM};
use crate::module_data::MODULE_DATA_SYM;
use crate::ModuleData;
use byteorder::{ByteOrder, LittleEndian};
use memoffset::offset_of;
pub use minisign::{PublicKey, SecretKey};
use minisign::{SignatureBones, SignatureBox};
use object::*;
use std::fs::{File, OpenOptions};
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};
use std::path::Path;

pub struct ModuleSignature;

impl ModuleSignature {
    pub fn verify<P: AsRef<Path>>(
        so_path: P,
        pk: &PublicKey,
        module_data: &ModuleData,
    ) -> Result<(), Error> {
        let signature_box: SignatureBox =
            SignatureBones::from_bytes(&module_data.get_module_signature())
                .map_err(|e| ModuleSignatureError(e))?
                .into();

        let mut raw_module_and_data =
            RawModuleAndData::from_file(&so_path).map_err(|e| IOError(e))?;
        let cleared_module_data_bin =
            ModuleData::clear_module_signature(raw_module_and_data.module_data_bin())?;
        raw_module_and_data.patch_module_data(&cleared_module_data_bin);

        minisign::verify(
            &pk,
            &signature_box,
            Cursor::new(&raw_module_and_data.obj_bin),
            true,
            false,
        )
        .map_err(|e| ModuleSignatureError(e))
    }

    pub fn sign<P: AsRef<Path>>(path: P, sk: &SecretKey) -> Result<(), Error> {
        let raw_module_and_data = RawModuleAndData::from_file(&path).map_err(|e| IOError(e))?;
        let signature_box = minisign::sign(
            None,
            sk,
            Cursor::new(&raw_module_and_data.obj_bin),
            true,
            None,
            None,
        )
        .map_err(|e| ModuleSignatureError(e))?;
        let signature_bones: SignatureBones = signature_box.into();
        let patched_module_data_bin = ModuleData::patch_module_signature(
            raw_module_and_data.module_data_bin(),
            &signature_bones.to_bytes(),
        )?;
        raw_module_and_data
            .write_patched_module_data(&path, &patched_module_data_bin)
            .map_err(|e| IOError(e))?;
        Ok(())
    }
}

#[allow(dead_code)]
struct SymbolData {
    offset: usize,
    len: usize,
}

struct RawModuleAndData {
    pub obj_bin: Vec<u8>,
    pub module_data_offset: usize,
    pub module_data_len: usize,
}

impl RawModuleAndData {
    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
        let mut obj_bin: Vec<u8> = Vec::new();
        File::open(&path)?.read_to_end(&mut obj_bin)?;

        let native_data_symbol_data =
            Self::symbol_data(&obj_bin, LUCET_MODULE_SYM, true)?.ok_or(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("`{}` symbol not present", LUCET_MODULE_SYM),
            ))?;

        // While `module_data` is the first field of the `SerializedModule` that `lucet_module` points
        // to, it is a virtual address, not a file offset. The translation is somewhat tricky at
        // the moment, so just look at the corresponding `lucet_module_data` symbol for now.
        let module_data_symbol_data =
            Self::symbol_data(&obj_bin, MODULE_DATA_SYM, true)?.ok_or(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("`{}` symbol not present", MODULE_DATA_SYM),
            ))?;

        let module_data_len = LittleEndian::read_u64(
            &obj_bin[(native_data_symbol_data.offset
                + offset_of!(SerializedModule, module_data_len))..],
        ) as usize;

        Ok(RawModuleAndData {
            obj_bin,
            module_data_offset: module_data_symbol_data.offset,
            module_data_len: module_data_len,
        })
    }

    pub fn module_data_bin(&self) -> &[u8] {
        &self.obj_bin[self.module_data_offset as usize
            ..self.module_data_offset as usize + self.module_data_len]
    }

    pub fn module_data_bin_mut(&mut self) -> &mut [u8] {
        &mut self.obj_bin[self.module_data_offset as usize
            ..self.module_data_offset as usize + self.module_data_len]
    }

    pub fn patch_module_data(&mut self, module_data_bin: &[u8]) {
        self.module_data_bin_mut().copy_from_slice(&module_data_bin);
    }

    pub fn write_patched_module_data<P: AsRef<Path>>(
        &self,
        path: P,
        patched_module_data_bin: &[u8],
    ) -> Result<(), io::Error> {
        let mut fp = OpenOptions::new()
            .write(true)
            .create_new(false)
            .open(&path)?;
        fp.seek(SeekFrom::Start(self.module_data_offset as u64))?;
        fp.write_all(&patched_module_data_bin)?;
        Ok(())
    }

    // Retrieving the offset of a symbol is not supported by the object crate.
    // In Mach-O, actual file offsets are encoded, whereas Elf encodes virtual
    // addresses, requiring extra steps to retrieve the section, its base
    // address as well as the section offset.

    // Elf
    #[cfg(all(target_family = "unix", not(target_os = "macos")))]
    fn symbol_data(
        obj_bin: &[u8],
        symbol_name: &str,
        _mangle: bool,
    ) -> Result<Option<SymbolData>, io::Error> {
        let obj = object::ElfFile::parse(obj_bin)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
        let symbol_map = obj.symbol_map();
        for symbol in symbol_map
            .symbols()
            .iter()
            .filter(|sym| sym.kind() == SymbolKind::Data)
            .filter(|sym| sym.name() == Some(symbol_name))
        {
            if let Some(section_index) = symbol.section_index() {
                let section = &obj.elf().section_headers[section_index.0];
                let offset = (symbol.address() - section.sh_addr + section.sh_offset) as usize;
                let len = symbol.size() as usize;
                return Ok(Some(SymbolData { offset, len }));
            }
        }
        Ok(None)
    }

    // Mach-O
    #[cfg(target_os = "macos")]
    fn symbol_data(
        obj_bin: &[u8],
        symbol_name: &str,
        mangle: bool,
    ) -> Result<Option<SymbolData>, io::Error> {
        let obj = object::File::parse(obj_bin)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
        let symbol_map = obj.symbol_map();
        let mangled_symbol_name = format!("_{}", symbol_name);
        let symbol_name = if mangle {
            &mangled_symbol_name
        } else {
            symbol_name
        };
        if let Some(symbol) = symbol_map
            .symbols()
            .iter()
            .filter(|sym| sym.kind() == SymbolKind::Data || sym.kind() == SymbolKind::Unknown)
            .find(|sym| sym.name() == Some(symbol_name))
        {
            let offset = symbol.address() as usize;
            let len = symbol.size() as usize;
            return Ok(Some(SymbolData { offset, len }));
        }
        Ok(None)
    }
}
<|endoftext|>