<commit_before>use std::panic;
use webcore::ffi;

/// Initializes the library.
///
/// Calling this is required for anything to work.
pub fn initialize() {
    static mut INITIALIZED: bool = false;
    unsafe {
        if INITIALIZED {
            return;
        }

        INITIALIZED = true;
    }

    js! { @(no_return)
        Module.STDWEB = {};
        Module.STDWEB.to_js = function to_js( address ) {
            var kind = HEAPU8[ address + 12 ];
            if( kind === 0 ) {
                return undefined;
            } else if( kind === 1 ) {
                return null;
            } else if( kind === 2 ) {
                return HEAP32[ address / 4 ];
            } else if( kind === 3 ) {
                return HEAPF64[ address / 8 ];
            } else if( kind === 4 ) {
                var pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                return Module.STDWEB.to_js_string( pointer, length );
            } else if( kind === 5 ) {
                return false;
            } else if( kind === 6 ) {
                return true;
            } else if( kind === 7 ) {
                var pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                var output = [];
                for( var i = 0; i < length; ++i ) {
                    output.push( Module.STDWEB.to_js( pointer + i * 16 ) );
                }
                return output;
            } else if( kind === 8 ) {
                var value_array_pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                var key_array_pointer = HEAPU32[ (address + 8) / 4 ];
                var output = {};
                for( var i = 0; i < length; ++i ) {
                    var key_pointer = HEAPU32[ (key_array_pointer + i * 8) / 4 ];
                    var key_length = HEAPU32[ (key_array_pointer + 4 + i * 8) / 4 ];
                    var key = Module.STDWEB.to_js_string( key_pointer, key_length );
                    var value = Module.STDWEB.to_js( value_array_pointer + i * 16 );
                    output[ key ] = value;
                }
                return output;
            } else if( kind === 9 ) {
                return Module.STDWEB.acquire_js_reference( HEAP32[ address / 4 ] );
            } else if( kind === 10 ) {
                var adapter_pointer = HEAPU32[ address / 4 ];
                var pointer = HEAPU32[ (address + 4) / 4 ];
                var deallocator_pointer = HEAPU32[ (address + 8) / 4 ];
                var output = function() {
                    var args = _malloc( 16 );
                    Module.STDWEB.from_js( args, arguments );
                    Runtime.dynCall( "vii", adapter_pointer, [pointer, args] );
                    var result = Module.STDWEB.tmp;
                    Module.STDWEB.tmp = null;

                    return result;
                };

                output.drop = function() {
                    output.drop = null;
                    Runtime.dynCall( "vi", deallocator_pointer, [pointer] );
                };

                return output;
            }
        };
    };

    js! { @(no_return)
        Module.STDWEB.from_js = function from_js( address, value ) {
            var kind = Object.prototype.toString.call( value );
            if( kind === "[object String]" ) {
                var length = lengthBytesUTF8( value );
                var pointer = _malloc( length + 1 );
                stringToUTF8( value, pointer, length + 1 );
                HEAPU8[ address + 12 ] = 4;
                HEAPU32[ address / 4 ] = pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
            } else if( kind === "[object Number]" ) {
                if( value === (value|0) ) {
                    HEAPU8[ address + 12 ] = 2;
                    HEAP32[ address / 4 ] = value;
                } else {
                    HEAPU8[ address + 12 ] = 3;
                    HEAPF64[ address / 8 ] = value;
                }
            } else if( value === null ) {
                HEAPU8[ address + 12 ] = 1;
            } else if( value === undefined ) {
                HEAPU8[ address + 12 ] = 0;
            } else if( value === false ) {
                HEAPU8[ address + 12 ] = 5;
            } else if( value === true ) {
                HEAPU8[ address + 12 ] = 6;
            } else if( kind === "[object Array]" || kind === "[object Arguments]" ) {
                var length = value.length;
                var pointer = _malloc( length * 16 );
                HEAPU8[ address + 12 ] = 7;
                HEAPU32[ address / 4 ] = pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
                for( var i = 0; i < length; ++i ) {
                    Module.STDWEB.from_js( pointer + i * 16, value[ i ] );
                }
            } else if( kind === "[object Object]" ) {
                var keys = Object.keys( value );
                var length = keys.length;
                var key_array_pointer = _malloc( length * 8 );
                var value_array_pointer = _malloc( length * 16 );
                HEAPU8[ address + 12 ] = 8;
                HEAPU32[ address / 4 ] = value_array_pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
                HEAPU32[ (address + 8) / 4 ] = key_array_pointer;
                for( var i = 0; i < length; ++i ) {
                    var key = keys[ i ];
                    var key_length = lengthBytesUTF8( key );
                    var key_pointer = _malloc( key_length + 1 );
                    stringToUTF8( key, key_pointer, key_length + 1 );

                    var key_address = key_array_pointer + i * 8;
                    HEAPU32[ key_address / 4 ] = key_pointer;
                    HEAPU32[ (key_address + 4) / 4 ] = key_length;

                    Module.STDWEB.from_js( value_array_pointer + i * 16, value[ key ] );
                }
            } else {
                var refid = Module.STDWEB.acquire_rust_reference( value );
                HEAPU8[ address + 12 ] = 9;
                HEAP32[ address / 4 ] = refid;
            }
        };
    };

    js! { @(no_return)
        // This is ported from Rust's stdlib; it's faster than
        // the string conversion from Emscripten.
        Module.STDWEB.to_js_string = function to_js_string( index, length ) {
            index = index|0;
            length = length|0;
            var end = (index|0) + (length|0);
            var output = "";
            while( index < end ) {
                var x = HEAPU8[ index++ ];
                if( x < 128 ) {
                    output += String.fromCharCode( x );
                    continue;
                }
                var init = (x & (0x7F >> 2));
                var y = 0;
                if( index < end ) {
                    y = HEAPU8[ index++ ];
                }
                var ch = (init << 6) | (y & 63);
                if( x >= 0xE0 ) {
                    var z = 0;
                    if( index < end ) {
                        z = HEAPU8[ index++ ];
                    }
                    var y_z = ((y & 63) << 6) | (z & 63);
                    ch = init << 12 | y_z;
                    if( x >= 0xF0 ) {
                        var w = 0;
                        if( index < end ) {
                            w = HEAPU8[ index++ ];
                        }
                        ch = (init & 7) << 18 | ((y_z << 6) | (w & 63));
                    }
                }
                output += String.fromCharCode( ch );
                continue;
            }
            return output;
        };
    };

    js! { @(no_return)
        var id_to_ref_map = {};
        var id_to_refcount_map = {};
        var ref_to_id_map = new WeakMap();
        var last_refid = 1;

        Module.STDWEB.acquire_rust_reference = function( reference ) {
            if( reference === undefined || reference === null ) {
                return 0;
            }

            var refid = ref_to_id_map.get( reference );
            if( refid === undefined ) {
                refid = last_refid++;
                ref_to_id_map.set( reference, refid );
                id_to_ref_map[ refid ] = reference;
                id_to_refcount_map[ refid ] = 1;
            } else {
                id_to_refcount_map[ refid ]++;
            }

            return refid;
        };

        Module.STDWEB.acquire_js_reference = function( refid ) {
            return id_to_ref_map[ refid ];
        };

        Module.STDWEB.increment_refcount = function( refid ) {
            id_to_refcount_map[ refid ]++;
        };

        Module.STDWEB.decrement_refcount = function( refid ) {
            id_to_refcount_map[ refid ]--;
            if( id_to_refcount_map[ refid ] === 0 ) {
                var reference = id_to_ref_map[ refid ];
                delete id_to_ref_map[ refid ];
                delete id_to_refcount_map[ refid ];
                ref_to_id_map.delete( reference );
            }
        };
    }

    if cfg!( test ) == false {
        panic::set_hook( Box::new( |info| {
            em_asm_int!( "console.error( 'Encountered a panic!' );" );
            if let Some( value ) = info.payload().downcast_ref::< String >() {
                em_asm_int!( "\
                    console.error( 'Panic error message:', Module.STDWEB.to_js_string( $0, $1 ) );\
                ", value.as_ptr(), value.len() );
            }
            if let Some( location ) = info.location() {
                let file = location.file();
                em_asm_int!( "\
                    console.error( 'Panic location:', Module.STDWEB.to_js_string( $0, $1 ) + ':' + $2 );\
                ", file.as_ptr(), file.len(), location.line() );
            }
        }));
    }
}

/// Runs the event loop.
///
/// You should call this before returning from `main()`,
/// otherwise bad things will happen.
pub fn event_loop() -> ! {
    unsafe {
        ffi::emscripten_set_main_loop( Some( ffi::emscripten_pause_main_loop ), 0, 1 );
    }

    unreachable!();
}
<commit_msg>Support passing symbols<commit_after>use std::panic;
use webcore::ffi;

/// Initializes the library.
///
/// Calling this is required for anything to work.
pub fn initialize() {
    static mut INITIALIZED: bool = false;
    unsafe {
        if INITIALIZED {
            return;
        }

        INITIALIZED = true;
    }

    js! { @(no_return)
        Module.STDWEB = {};
        Module.STDWEB.to_js = function to_js( address ) {
            var kind = HEAPU8[ address + 12 ];
            if( kind === 0 ) {
                return undefined;
            } else if( kind === 1 ) {
                return null;
            } else if( kind === 2 ) {
                return HEAP32[ address / 4 ];
            } else if( kind === 3 ) {
                return HEAPF64[ address / 8 ];
            } else if( kind === 4 ) {
                var pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                return Module.STDWEB.to_js_string( pointer, length );
            } else if( kind === 5 ) {
                return false;
            } else if( kind === 6 ) {
                return true;
            } else if( kind === 7 ) {
                var pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                var output = [];
                for( var i = 0; i < length; ++i ) {
                    output.push( Module.STDWEB.to_js( pointer + i * 16 ) );
                }
                return output;
            } else if( kind === 8 ) {
                var value_array_pointer = HEAPU32[ address / 4 ];
                var length = HEAPU32[ (address + 4) / 4 ];
                var key_array_pointer = HEAPU32[ (address + 8) / 4 ];
                var output = {};
                for( var i = 0; i < length; ++i ) {
                    var key_pointer = HEAPU32[ (key_array_pointer + i * 8) / 4 ];
                    var key_length = HEAPU32[ (key_array_pointer + 4 + i * 8) / 4 ];
                    var key = Module.STDWEB.to_js_string( key_pointer, key_length );
                    var value = Module.STDWEB.to_js( value_array_pointer + i * 16 );
                    output[ key ] = value;
                }
                return output;
            } else if( kind === 9 ) {
                return Module.STDWEB.acquire_js_reference( HEAP32[ address / 4 ] );
            } else if( kind === 10 ) {
                var adapter_pointer = HEAPU32[ address / 4 ];
                var pointer = HEAPU32[ (address + 4) / 4 ];
                var deallocator_pointer = HEAPU32[ (address + 8) / 4 ];
                var output = function() {
                    var args = _malloc( 16 );
                    Module.STDWEB.from_js( args, arguments );
                    Runtime.dynCall( "vii", adapter_pointer, [pointer, args] );
                    var result = Module.STDWEB.tmp;
                    Module.STDWEB.tmp = null;

                    return result;
                };

                output.drop = function() {
                    output.drop = null;
                    Runtime.dynCall( "vi", deallocator_pointer, [pointer] );
                };

                return output;
            }
        };
    };

    js! { @(no_return)
        Module.STDWEB.from_js = function from_js( address, value ) {
            var kind = Object.prototype.toString.call( value );
            if( kind === "[object String]" ) {
                var length = lengthBytesUTF8( value );
                var pointer = _malloc( length + 1 );
                stringToUTF8( value, pointer, length + 1 );
                HEAPU8[ address + 12 ] = 4;
                HEAPU32[ address / 4 ] = pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
            } else if( kind === "[object Number]" ) {
                if( value === (value|0) ) {
                    HEAPU8[ address + 12 ] = 2;
                    HEAP32[ address / 4 ] = value;
                } else {
                    HEAPU8[ address + 12 ] = 3;
                    HEAPF64[ address / 8 ] = value;
                }
            } else if( value === null ) {
                HEAPU8[ address + 12 ] = 1;
            } else if( value === undefined ) {
                HEAPU8[ address + 12 ] = 0;
            } else if( value === false ) {
                HEAPU8[ address + 12 ] = 5;
            } else if( value === true ) {
                HEAPU8[ address + 12 ] = 6;
            } else if( kind === "[object Array]" || kind === "[object Arguments]" ) {
                var length = value.length;
                var pointer = _malloc( length * 16 );
                HEAPU8[ address + 12 ] = 7;
                HEAPU32[ address / 4 ] = pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
                for( var i = 0; i < length; ++i ) {
                    Module.STDWEB.from_js( pointer + i * 16, value[ i ] );
                }
            } else if( kind === "[object Object]" ) {
                var keys = Object.keys( value );
                var length = keys.length;
                var key_array_pointer = _malloc( length * 8 );
                var value_array_pointer = _malloc( length * 16 );
                HEAPU8[ address + 12 ] = 8;
                HEAPU32[ address / 4 ] = value_array_pointer;
                HEAPU32[ (address + 4) / 4 ] = length;
                HEAPU32[ (address + 8) / 4 ] = key_array_pointer;
                for( var i = 0; i < length; ++i ) {
                    var key = keys[ i ];
                    var key_length = lengthBytesUTF8( key );
                    var key_pointer = _malloc( key_length + 1 );
                    stringToUTF8( key, key_pointer, key_length + 1 );

                    var key_address = key_array_pointer + i * 8;
                    HEAPU32[ key_address / 4 ] = key_pointer;
                    HEAPU32[ (key_address + 4) / 4 ] = key_length;

                    Module.STDWEB.from_js( value_array_pointer + i * 16, value[ key ] );
                }
            } else {
                var refid = Module.STDWEB.acquire_rust_reference( value );
                HEAPU8[ address + 12 ] = 9;
                HEAP32[ address / 4 ] = refid;
            }
        };
    };

    js! { @(no_return)
        // This is ported from Rust's stdlib; it's faster than
        // the string conversion from Emscripten.
        Module.STDWEB.to_js_string = function to_js_string( index, length ) {
            index = index|0;
            length = length|0;
            var end = (index|0) + (length|0);
            var output = "";
            while( index < end ) {
                var x = HEAPU8[ index++ ];
                if( x < 128 ) {
                    output += String.fromCharCode( x );
                    continue;
                }
                var init = (x & (0x7F >> 2));
                var y = 0;
                if( index < end ) {
                    y = HEAPU8[ index++ ];
                }
                var ch = (init << 6) | (y & 63);
                if( x >= 0xE0 ) {
                    var z = 0;
                    if( index < end ) {
                        z = HEAPU8[ index++ ];
                    }
                    var y_z = ((y & 63) << 6) | (z & 63);
                    ch = init << 12 | y_z;
                    if( x >= 0xF0 ) {
                        var w = 0;
                        if( index < end ) {
                            w = HEAPU8[ index++ ];
                        }
                        ch = (init & 7) << 18 | ((y_z << 6) | (w & 63));
                    }
                }
                output += String.fromCharCode( ch );
                continue;
            }
            return output;
        };
    };

    js! { @(no_return)
        var id_to_ref_map = {};
        var id_to_refcount_map = {};
        var ref_to_id_map = new WeakMap();
        var ref_to_id_symbol_map = {};
        var last_refid = 1;

        Module.STDWEB.acquire_rust_reference = function( reference ) {
            if( reference === undefined || reference === null ) {
                return 0;
            }

            var refid = ref_to_id_map.get( reference );
            if( refid === undefined ) {
                refid = ref_to_id_symbol_map[ reference ];
            }

            if( refid === undefined ) {
                refid = last_refid++;
                if( typeof reference === "symbol" ) {
                    ref_to_id_symbol_map[ reference ] = refid;
                } else {
                    ref_to_id_map.set( reference, refid );
                }
                id_to_ref_map[ refid ] = reference;
                id_to_refcount_map[ refid ] = 1;
            } else {
                id_to_refcount_map[ refid ]++;
            }

            return refid;
        };

        Module.STDWEB.acquire_js_reference = function( refid ) {
            return id_to_ref_map[ refid ];
        };

        Module.STDWEB.increment_refcount = function( refid ) {
            id_to_refcount_map[ refid ]++;
        };

        Module.STDWEB.decrement_refcount = function( refid ) {
            id_to_refcount_map[ refid ]--;
            if( id_to_refcount_map[ refid ] === 0 ) {
                var reference = id_to_ref_map[ refid ];
                delete id_to_ref_map[ refid ];
                delete id_to_refcount_map[ refid ];
                if( typeof reference === "symbol" ) {
                    delete ref_to_id_symbol_map[ reference ];
                } else {
                    ref_to_id_map.delete( reference );
                }
            }
        };
    }

    if cfg!( test ) == false {
        panic::set_hook( Box::new( |info| {
            em_asm_int!( "console.error( 'Encountered a panic!' );" );
            if let Some( value ) = info.payload().downcast_ref::< String >() {
                em_asm_int!( "\
                    console.error( 'Panic error message:', Module.STDWEB.to_js_string( $0, $1 ) );\
                ", value.as_ptr(), value.len() );
            }
            if let Some( location ) = info.location() {
                let file = location.file();
                em_asm_int!( "\
                    console.error( 'Panic location:', Module.STDWEB.to_js_string( $0, $1 ) + ':' + $2 );\
                ", file.as_ptr(), file.len(), location.line() );
            }
        }));
    }
}

/// Runs the event loop.
///
/// You should call this before returning from `main()`,
/// otherwise bad things will happen.
pub fn event_loop() -> ! {
    unsafe {
        ffi::emscripten_set_main_loop( Some( ffi::emscripten_pause_main_loop ), 0, 1 );
    }

    unreachable!();
}
<|endoftext|>


<commit_before>use document;
use ffi;

use std::from_str::from_str;
use std::result;
use std::int;
use std::f64;

pub trait YamlConstructor<T, E> {
    fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result<T, E>;
    fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result<T, E>;
    fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result<T, E>;

    fn construct<'r>(&self, node: document::YamlNode<'r>) -> Result<T, E> {
        match node {
            document::YamlScalarNode(scalar) => self.construct_scalar(scalar),
            document::YamlSequenceNode(sequence) => self.construct_sequence(sequence),
            document::YamlMappingNode(mapping) => self.construct_mapping(mapping)
        }
    }
}

#[deriving(Eq)]
#[deriving(Show)]
pub enum YamlStandardData {
    YamlInteger(int),
    YamlFloat(f64),
    YamlString(~str),
    YamlNull,
    YamlBool(bool),
    YamlSequence(~[YamlStandardData]),
    YamlMapping(~[(YamlStandardData, YamlStandardData)]),
}

pub struct YamlStandardConstructor;

impl YamlStandardConstructor {
    pub fn new() -> YamlStandardConstructor {
        YamlStandardConstructor
    }
}

impl YamlConstructor<YamlStandardData, ~str> for YamlStandardConstructor {
    fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result<YamlStandardData, ~str> {
        let dec_int = regex!(r"^[-+]?[0-9]+$");
        let oct_int = regex!(r"^0o[0-7]+$");
        let hex_int = regex!(r"^0x[0-9a-fA-F]+$");
        let float_pattern = regex!(r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$");
        let pos_inf = regex!(r"^[+]?(\.inf|\.Inf|\.INF)$");
        let neg_inf = regex!(r"^-(\.inf|\.Inf|\.INF)$");
        let nan = regex!(r"^(\.nan|\.NaN|\.NAN)$");
        let null = regex!(r"^(null|Null|NULL|~)$");
        let true_pattern = regex!(r"^(true|True|TRUE|yes|Yes|YES)$");
        let false_pattern = regex!(r"^(false|False|FALSE|no|No|NO)$");

        let value = scalar.get_value();

        match scalar.style() {
            ffi::YamlPlainScalarStyle => {
                if dec_int.is_match(value) {
                    Ok(YamlInteger(from_str(value).unwrap()))
                } else if oct_int.is_match(value) {
                    let num_part = value.slice_from(2);
                    Ok(YamlInteger(int::parse_bytes(num_part.as_bytes(), 8).unwrap()))
                } else if hex_int.is_match(value) {
                    let num_part = value.slice_from(2);
                    Ok(YamlInteger(int::parse_bytes(num_part.as_bytes(), 16).unwrap()))
                } else if float_pattern.is_match(value) {
                    Ok(YamlFloat(from_str(value).unwrap()))
                } else if pos_inf.is_match(value) {
                    Ok(YamlFloat(f64::INFINITY))
                } else if neg_inf.is_match(value) {
                    Ok(YamlFloat(f64::NEG_INFINITY))
                } else if nan.is_match(value) {
                    Ok(YamlFloat(f64::NAN))
                } else if null.is_match(value) {
                    Ok(YamlNull)
                } else if true_pattern.is_match(value) {
                    Ok(YamlBool(true))
                } else if false_pattern.is_match(value) {
                    Ok(YamlBool(false))
                } else {
                    Ok(YamlString(value))
                }
            },
            _ => {
                Ok(YamlString(value))
            }
        }
    }

    fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result<YamlStandardData, ~str> {
        result::collect(sequence.values().map(|node| { self.construct(node) })).map(|list| YamlSequence(list))
    }

    fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result<YamlStandardData, ~str> {
        let pairs = mapping.pairs().map(|(key_node, value_node)| {
            match self.construct(key_node) {
                Ok(key) => match self.construct(value_node) {
                    Ok(value) => Ok((key, value)),
                    Err(e) => Err(e)
                },
                Err(e) => Err(e)
            }
        });
        result::collect(pairs).map(YamlMapping)
    }
}

#[cfg(test)]
mod test {
    use parser::{YamlParser, YamlByteParser};
    use constructor::*;
    use std::f64;

    #[test]
    fn test_standard_constructor() {
        let data = "[1, 2, 3]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlInteger(1), YamlInteger(2), YamlInteger(3)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("{:?}", err)
        }
    }

    #[test]
    fn test_integer_parser() {
        let data = "[0o10, 0x21, -30]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlInteger(0o10), YamlInteger(0x21), YamlInteger(-30)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("{:?}", err)
        }
    }

    #[test]
    fn test_float_parser() {
        let data = "[0.3, -.4, 1e+2, -1.2e-3]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                let value = ctor.construct(doc.root());
                match value {
                    Ok(YamlSequence(seq)) => {
                        match seq.as_slice() {
                            [YamlFloat(f1), YamlFloat(f2), YamlFloat(f3), YamlFloat(f4)] => {
                                assert!((f1 - 0.3).abs() < 1.0e-6);
                                assert!((f2 + 0.4).abs() < 1.0e-6);
                                assert!((f3 - 1e+2).abs() < 1.0e-6);
                                assert!((f4 + 1.2e-3).abs() < 1.0e-6);
                            },
                            _ => fail!("unexpected sequence: {:?}", seq)
                        }
                    },
                    _ => fail!("unexpected result: {:?}", value)
                }
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }

    #[test]
    fn test_inf_parser() {
        let data = "[.inf, -.INF]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlFloat(f64::INFINITY), YamlFloat(f64::NEG_INFINITY)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }

    #[test]
    fn test_misc_parser() {
        let data = "[yes, False, ~]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlBool(true), YamlBool(false), YamlNull])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }
}
<commit_msg>Double quoted string parser<commit_after>use document;
use document::YamlNodeData;
use ffi;
use parser::YamlMark;

use std::from_str::from_str;
use std::result;
use std::int;
use std::f64;
use std::u32;
use std::char;
use std::strbuf::StrBuf;

pub trait YamlConstructor<T, E> {
    fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result<T, E>;
    fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result<T, E>;
    fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result<T, E>;

    fn construct<'r>(&self, node: document::YamlNode<'r>) -> Result<T, E> {
        match node {
            document::YamlScalarNode(scalar) => self.construct_scalar(scalar),
            document::YamlSequenceNode(sequence) => self.construct_sequence(sequence),
            document::YamlMappingNode(mapping) => self.construct_mapping(mapping)
        }
    }
}

#[deriving(Eq)]
#[deriving(Show)]
pub enum YamlStandardData {
    YamlInteger(int),
    YamlFloat(f64),
    YamlString(~str),
    YamlNull,
    YamlBool(bool),
    YamlSequence(~[YamlStandardData]),
    YamlMapping(~[(YamlStandardData, YamlStandardData)]),
}

pub struct YamlStandardConstructor;

impl YamlStandardConstructor {
    pub fn new() -> YamlStandardConstructor {
        YamlStandardConstructor
    }

    pub fn parse_double_quoted(value: &str, mark: &YamlMark) -> Result<~str, ~str> {
        let mut buf = StrBuf::new();
        let mut it = value.chars();

        loop {
            match it.next() {
                None => return Ok(buf.into_owned()),
                Some('\\') => {
                    // escape sequences
                    match it.next() {
                        None => return Err(format!("invalid escape sequence at line {:u}, col {:u}", mark.line, mark.column)),
                        Some('0') => buf.push_char('\x00'),
                        Some('a') => buf.push_char('\x07'),
                        Some('b') => buf.push_char('\x08'),
                        Some('t') | Some('\t') => buf.push_char('\t'),
                        Some('n') => buf.push_char('\n'),
                        Some('v') => buf.push_char('\x0b'),
                        Some('f') => buf.push_char('\x0c'),
                        Some('r') => buf.push_char('\x0d'),
                        Some('e') => buf.push_char('\x1b'),
                        Some('N') => buf.push_char('\x85'),
                        Some('_') => buf.push_char('\xa0'),
                        Some('L') => buf.push_char('\u2028'),
                        Some('P') => buf.push_char('\u2029'),
                        Some('x') => {
                            let code:~str = it.take(2).collect();
                            match parse_escape_sequence(code, 2) {
                                Some(c) => buf.push_char(c),
                                None => return Err(format!("invalid x escape sequence at line {:u}, col {:u}", mark.line, mark.column))
                            }
                        },
                        Some('u') => {
                            let code:~str = it.take(4).collect();
                            match parse_escape_sequence(code, 4) {
                                Some(c) => buf.push_char(c),
                                None => return Err(format!("invalid x escape sequence at line {:u}, col {:u}", mark.line, mark.column))
                            }
                        },
                        Some('U') => {
                            let code:~str = it.take(8).collect();
                            match parse_escape_sequence(code, 8) {
                                Some(c) => buf.push_char(c),
                                None => return Err(format!("invalid x escape sequence at line {:u}, col {:u}", mark.line, mark.column))
                            }
                        },
                        Some(c) => buf.push_char(c)
                    }
                },
                Some(c) => buf.push_char(c)
            }
        }
    }
}

fn parse_escape_sequence(rep: ~str, expected_len: uint) -> Option<char> {
    match u32::parse_bytes(rep.as_bytes(), 16) {
        Some(code) if rep.len() == expected_len => char::from_u32(code),
        _ => None
    }
}

impl YamlConstructor<YamlStandardData, ~str> for YamlStandardConstructor {
    fn construct_scalar(&self, scalar: document::YamlScalarData) -> Result<YamlStandardData, ~str> {
        let dec_int = regex!(r"^[-+]?[0-9]+$");
        let oct_int = regex!(r"^0o[0-7]+$");
        let hex_int = regex!(r"^0x[0-9a-fA-F]+$");
        let float_pattern = regex!(r"^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$");
        let pos_inf = regex!(r"^[+]?(\.inf|\.Inf|\.INF)$");
        let neg_inf = regex!(r"^-(\.inf|\.Inf|\.INF)$");
        let nan = regex!(r"^(\.nan|\.NaN|\.NAN)$");
        let null = regex!(r"^(null|Null|NULL|~)$");
        let true_pattern = regex!(r"^(true|True|TRUE|yes|Yes|YES)$");
        let false_pattern = regex!(r"^(false|False|FALSE|no|No|NO)$");

        let value = scalar.get_value();
        let mark = scalar.start_mark();

        match scalar.style() {
            ffi::YamlPlainScalarStyle => {
                if dec_int.is_match(value) {
                    Ok(YamlInteger(from_str(value).unwrap()))
                } else if oct_int.is_match(value) {
                    let num_part = value.slice_from(2);
                    Ok(YamlInteger(int::parse_bytes(num_part.as_bytes(), 8).unwrap()))
                } else if hex_int.is_match(value) {
                    let num_part = value.slice_from(2);
                    Ok(YamlInteger(int::parse_bytes(num_part.as_bytes(), 16).unwrap()))
                } else if float_pattern.is_match(value) {
                    Ok(YamlFloat(from_str(value).unwrap()))
                } else if pos_inf.is_match(value) {
                    Ok(YamlFloat(f64::INFINITY))
                } else if neg_inf.is_match(value) {
                    Ok(YamlFloat(f64::NEG_INFINITY))
                } else if nan.is_match(value) {
                    Ok(YamlFloat(f64::NAN))
                } else if null.is_match(value) {
                    Ok(YamlNull)
                } else if true_pattern.is_match(value) {
                    Ok(YamlBool(true))
                } else if false_pattern.is_match(value) {
                    Ok(YamlBool(false))
                } else {
                    Ok(YamlString(value))
                }
            },
            ffi::YamlDoubleQuotedScalarStyle => {
                YamlStandardConstructor::parse_double_quoted(value, &mark).map(YamlString)
            },
            _ => {
                Ok(YamlString(value))
            }
        }
    }

    fn construct_sequence(&self, sequence: document::YamlSequenceData) -> Result<YamlStandardData, ~str> {
        result::collect(sequence.values().map(|node| { self.construct(node) })).map(|list| YamlSequence(list))
    }

    fn construct_mapping(&self, mapping: document::YamlMappingData) -> Result<YamlStandardData, ~str> {
        let pairs = mapping.pairs().map(|(key_node, value_node)| {
            match self.construct(key_node) {
                Ok(key) => match self.construct(value_node) {
                    Ok(value) => Ok((key, value)),
                    Err(e) => Err(e)
                },
                Err(e) => Err(e)
            }
        });
        result::collect(pairs).map(YamlMapping)
    }
}

#[cfg(test)]
mod test {
    use parser::{YamlParser, YamlByteParser};
    use constructor::*;
    use std::f64;

    #[test]
    fn test_standard_constructor() {
        let data = "[1, 2, 3]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlInteger(1), YamlInteger(2), YamlInteger(3)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("{:?}", err)
        }
    }

    #[test]
    fn test_integer_parser() {
        let data = "[0o10, 0x21, -30]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlInteger(0o10), YamlInteger(0x21), YamlInteger(-30)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("{:?}", err)
        }
    }

    #[test]
    fn test_float_parser() {
        let data = "[0.3, -.4, 1e+2, -1.2e-3]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                let value = ctor.construct(doc.root());
                match value {
                    Ok(YamlSequence(seq)) => {
                        match seq.as_slice() {
                            [YamlFloat(f1), YamlFloat(f2), YamlFloat(f3), YamlFloat(f4)] => {
                                assert!((f1 - 0.3).abs() < 1.0e-6);
                                assert!((f2 + 0.4).abs() < 1.0e-6);
                                assert!((f3 - 1e+2).abs() < 1.0e-6);
                                assert!((f4 + 1.2e-3).abs() < 1.0e-6);
                            },
                            _ => fail!("unexpected sequence: {:?}", seq)
                        }
                    },
                    _ => fail!("unexpected result: {:?}", value)
                }
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }

    #[test]
    fn test_inf_parser() {
        let data = "[.inf, -.INF]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlFloat(f64::INFINITY), YamlFloat(f64::NEG_INFINITY)])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }

    #[test]
    fn test_misc_parser() {
        let data = "[yes, False, ~]";
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlSequence(~[YamlBool(true), YamlBool(false), YamlNull])), ctor.construct(doc.root()))
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }

    #[test]
    fn test_double_quoted_parser() {
        let data = r#""hello, \"world\"""#;
        let parser = YamlByteParser::init(data.as_bytes());

        match parser.load().next_document() {
            Ok(doc) => {
                let ctor = YamlStandardConstructor::new();
                assert_eq!(Ok(YamlString("hello, \"world\"".to_owned())), ctor.construct(doc.root()))
            }
            Err(err) => fail!("document parse failure: {:?}", err)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::{ensure, Result};
use libra_logger::prelude::*;
use libradb::LibraDB;
use std::path::PathBuf;
use transaction_builder::get_transaction_name;

use libra_crypto::hash::{CryptoHash, EventAccumulatorHasher};
use libra_crypto::HashValue;
use libra_types::contract_event::ContractEvent;
use libra_types::proof::accumulator::InMemoryAccumulator;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(long, parse(from_os_str))]
    db: PathBuf,
}

/// Print out latest information stored in the DB.
fn print_head(db: &LibraDB) {
    let version = db
        .get_latest_version()
        .expect("get_latest_version throw error");

    info!("Latest Version: {}", version);

    let si = db
        .get_startup_info()
        .expect("Can't get startup info")
        .expect("StartupInfo is empty, database is empty.");

    info!(
        "The latest ledger info: {}",
        si.latest_ledger_info.ledger_info()
    );

    info!("Signatures: {:?}", si.latest_ledger_info.signatures());

    info!(
        "Current Validator Set: {}",
        si.latest_validator_set
            .expect("Unable to determine validator set, DB incorrect")
    );

    let tx = db
        .get_transaction_with_proof(version, version, false)
        .expect("Unable to load latest TXN");
    info!(
        "Current Transaction: {}",
        tx.transaction.format_for_client(get_transaction_name)
    );
}

/// List all TXNs from DB and verify their proofs
fn verify_txns(db: &LibraDB) -> Result<()> {
    let si = db
        .get_startup_info()
        .expect("Can't get startup info")
        .expect("StartupInfo is empty, database is empty.");
    let ledger_info = si.latest_ledger_info.ledger_info();

    let latest_version = ledger_info.version();

    for n in (1..latest_version).rev() {
        let tx = db.get_transaction_with_proof(n, latest_version, true)?;

        let events_root_hash = tx.events.as_ref().map(|events| {
            let event_hashes: Vec<_> = events.iter().map(ContractEvent::hash).collect();
            InMemoryAccumulator::<EventAccumulatorHasher>::from_leaves(&event_hashes).root_hash()
        });

        // verify TX proof
        tx.proof
            .verify(ledger_info, tx.transaction.hash(), events_root_hash, n)?;
    }
    info!("Total TXNs verified: {}", latest_version);

    Ok(())
}

// Verify the last accounts state tree by iterating through all accounts
fn verify_latest_account_state(db: &LibraDB) -> Result<()> {
    let version = db.get_latest_version()?;
    let backup = db.get_backup_handler();

    let iter = backup.get_account_iter(version)?;

    let mut total = 0;
    for (i, item) in iter.enumerate() {
        let (addr_hash, blob) = item?;
        ensure!(addr_hash != HashValue::zero(), "Invalid address hash!");
        ensure!(blob.hash() != HashValue::zero(), "Invalid blob!");
        total = i;
    }
    info!("Total account verified: {}", total + 1);

    // TODO: verify the root hash is correct

    Ok(())
}

fn main() {
    let _logger = libra_logger::set_global_logger(false, None);

    let opt = Opt::from_args();

    let p = opt.db.as_path();

    if !p.is_dir() {
        info!("Invalid Directory {:?}!", p);
        std::process::exit(-1);
    }

    let log_dir = tempfile::tempdir().expect("Unable to get temp dir");
    info!("Opening DB at: {:?}, log at {:?}", p, log_dir.path());

    let db = LibraDB::open(p, true, Some(log_dir.path())).expect("Unable to open LibraDB");
    info!("DB opened successfully.");

    print_head(&db);

    verify_txns(&db).expect("Unable to verify all TXNs");

    verify_latest_account_state(&db).expect("Unable to verify account state");

    info!("Successfully verified database.");
}
<commit_msg>Implement list-txn, print-txn, print-account commands. Remove all verification checks.<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use anyhow::Result;
use libra_logger::prelude::*;
use libradb::LibraDB;
use std::path::PathBuf;
use transaction_builder::get_transaction_name;

use libra_types::{account_address::AccountAddress, account_config::AccountResource};
use std::convert::TryFrom;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    #[structopt(long, parse(from_os_str))]
    db: PathBuf,

    #[structopt(subcommand)] // Note that we mark a field as a subcommand
    cmd: Option<Command>,
}

#[derive(Debug, StructOpt)]
enum Command {
    #[structopt(name = "list-txns")]
    ListTXNs,
    #[structopt(name = "print-txn")]
    PrintTXN { version: u64 },
    #[structopt(name = "print-account")]
    PrintAccount {
        #[structopt(parse(try_from_str))]
        address: AccountAddress,
    },
}

/// Print out latest information stored in the DB.
fn print_head(db: &LibraDB) -> Result<()> {
    let si = db
        .get_startup_info()
        .expect("Can't get startup info")
        .expect("StartupInfo is empty, database is empty.");

    let version = si.latest_ledger_info.ledger_info().version();
    info!("Version: {}", version);

    info!(
        "The latest ledger info: {}",
        si.latest_ledger_info.ledger_info()
    );

    info!("Signatures: {:?}", si.latest_ledger_info.signatures());

    info!(
        "Current Validator Set: {}",
        si.latest_validator_set
            .expect("Unable to determine validator set, DB incorrect")
    );

    let backup = db.get_backup_handler();
    let iter = backup.get_account_iter(version)?;
    let num_account_state = iter.count();
    info!("Total Accounts: {}", num_account_state);

    print_txn(db, version);

    Ok(())
}

fn print_txn(db: &LibraDB, version: u64) {
    let tx = db
        .get_transaction_with_proof(version, version, false)
        .expect("Unable to load latest TXN");
    println!(
        "Transaction {}: {}",
        version,
        tx.transaction.format_for_client(get_transaction_name)
    );
}

fn print_account(db: &LibraDB, addr: AccountAddress) {
    let maybe_blob = db
        .get_latest_account_state(addr)
        .expect("Unable to read AccountState");
    if let Some(blob) = maybe_blob {
        match AccountResource::try_from(&blob) {
            Ok(r) => {
                println!("Account {}: {:?}", addr, r);
            }
            Err(e) => {
                info!(
                    "Account {} exists, but have no AccountResource: {}.",
                    addr, e
                );
            }
        }
    } else {
        info!("Account {} doesn't exists", addr);
    }
}

fn list_txns(db: &LibraDB) {
    let version = db
        .get_latest_version()
        .expect("Unable to get latest version");
    let backup = db.get_backup_handler();
    let iter = backup
        .get_transaction_iter(0, version)
        .expect("Unable to get txn iter");
    for (v, tx) in iter.enumerate() {
        println!(
            "TXN {}: {}",
            v,
            tx.expect("Unable to read TX")
                .format_for_client(get_transaction_name)
        );
    }
}

fn main() {
    let _logger = libra_logger::set_global_logger(false, None);

    let opt = Opt::from_args();

    let p = opt.db.as_path();

    if !p.is_dir() {
        info!("Invalid Directory {:?}!", p);
        std::process::exit(-1);
    }

    let log_dir = tempfile::tempdir().expect("Unable to get temp dir");
    info!("Opening DB at: {:?}, log at {:?}", p, log_dir.path());

    let db = LibraDB::open(p, true, Some(log_dir.path())).expect("Unable to open LibraDB");
    info!("DB opened successfully.");

    if let Some(cmd) = opt.cmd {
        match cmd {
            Command::ListTXNs => {
                list_txns(&db);
            }
            Command::PrintTXN { version } => {
                print_txn(&db, version);
            }
            Command::PrintAccount { address } => {
                print_account(&db, address);
            }
        }
    } else {
        print_head(&db).expect("Unable to read information from DB");

        Opt::clap().print_help().unwrap();
        println!();
    }
}
<|endoftext|>


<commit_before><commit_msg>uucore: remove an inaccurate comment<commit_after><|endoftext|>


<commit_before>use super::RawLink;

use core::mem;

const MIN_ALIGN: usize = 4096;

pub struct Free { next: RawLink<Free> }

pub struct FreeList<'a> {
    /// A pointer to the head of the free list
    head: Option<&'a mut Free>
  , /// Number of blocks in the free list
    pub length: usize
}

impl<'a> FreeList<'a> {

    /// Create a new empty `FreeList`
    const fn new() -> FreeList<'a> {
        FreeList { head: None, length: 0 }
    }

    /// Push a new block onto the free list
    ///
    /// # Unsafe due to
    ///   - `mem::transmute()`
    ///   - Dereferencing a raw pointer
    unsafe fn push(&mut self, block: *mut u8) {
        let block_ptr = block as *mut Free;
        // be nice if rawlink was kinder to pattern-matching but whatever
        *block_ptr = if let Some(head) = self.head.take() {
            Free { next: RawLink::some(head) }
        } else {
            Free { next: RawLink::none() }
        };
        self.head = Some(mem::transmute(block_ptr));
        self.length += 1;
    }
    /// Pop the head block off of the free list.
    ///
    /// # Returns
    ///   - `Some(*mut u8)` if the free list has blocks left
    ///   - `None` if the free list is empty
    ///
    /// # Unsafe due to
    ///   - `mem::transmute()`
    ///   - Dereferencing a raw pointer
    unsafe fn pop(&mut self) -> Option<*mut u8> {
        self.head.take()
            .map(|head| {
                let popped_block
                    = mem::replace(&mut self.head, head.next.resolve_mut());
                let block_ptr: *mut u8
                    = mem::transmute(popped_block);
                block_ptr
            })
    }

    fn iter<'b: 'a>(&'b self) -> FreeListIter<'b> {
        // FreeListIter { current: self.head.map(|c| c.borrow())
        //                             .as_ref()
        //              }
        unimplemented!()
    }

    fn iter_mut<'b>(&'b mut self) -> FreeListIterMut<'b> {
        // FreeListIterMut { current: self.head.map(|c| *c ).as_mut() }
        unimplemented!()
    }
}

struct FreeListIter<'a> {
    current: Option<&'a Free>
}

impl<'a> Iterator for FreeListIter<'a> {
    type Item = &'a Free;

    fn next(&mut self) -> Option<&'a Free> {
        self.current
            .map(|c| {
                self.current = unsafe { c.next.resolve() };
                c
            })
    }
}

struct FreeListIterMut<'a> {
    current: Option<&'a mut Free>
}

impl<'a> Iterator for FreeListIterMut<'a> {
    type Item = &'a mut Free;

    fn next(&mut self) -> Option<&'a mut Free> {
        self.current.take()
            .map(|c| {
                self.current = unsafe { c.next.resolve_mut() };
                c
            })
    }
}

pub struct BuddyHeapAllocator<'a> {
    /// Address of the base of the heap. This must be aligned
    /// on a `MIN_ALIGN` boundary.
    start_addr: *mut u8
  , /// The allocator's free list
    free_lists: &'a mut [FreeList<'a>]
  , /// Number of blocks in the heap (must be a power of 2)
    heap_size: usize
  , /// Minimum block size
    min_block_size: usize
}

impl<'a> BuddyHeapAllocator<'a> {
    pub unsafe fn new( start_addr: *mut u8
                     , free_lists: &'a mut [FreeList<'a>]
                     , heap_size: usize)
                     -> BuddyHeapAllocator<'a>
    {
        let n_free_lists = free_lists.len();

        assert!( !start_addr.is_null()
                , "Heap start address cannot be null." );
        assert!( n_free_lists > 0
               , "Allocator must have at least one free list.");
        assert!( start_addr as usize & (MIN_ALIGN-1) == 0
               , "Heap start address must be aligned on a 4k boundary.");

        let min_block_size = heap_size >> (n_free_lists - 1);

        assert!( heap_size >= min_block_size
               , "Heap must be large enough to contain at least one block.");
        assert!( min_block_size >= mem::size_of::<Free>()
               , "Minimum block size must be large enough to contain \
                  the free block header.");

        let mut heap
            = BuddyHeapAllocator { start_addr: start_addr
                                 , free_lists: free_lists
                                 , heap_size: heap_size
                                 , min_block_size: min_block_size
                                 };
        // TODO: put first head block on appropriately-sized freelist
        heap
    }
}
<commit_msg>Free list iterators actually work now?<commit_after>use super::RawLink;

use core::mem;

const MIN_ALIGN: usize = 4096;

pub struct Free { next: RawLink<Free> }

pub struct FreeList<'a> {
    /// A pointer to the head of the free list
    head: Option<&'a mut Free>
  , /// Number of blocks in the free list
    pub length: usize
}

impl<'a> FreeList<'a> {

    /// Create a new empty `FreeList`
    const fn new() -> FreeList<'a> {
        FreeList { head: None, length: 0 }
    }

    /// Push a new block onto the free list
    ///
    /// # Unsafe due to
    ///   - `mem::transmute()`
    ///   - Dereferencing a raw pointer
    unsafe fn push(&mut self, block: *mut u8) {
        let block_ptr = block as *mut Free;
        // be nice if rawlink was kinder to pattern-matching but whatever
        *block_ptr = if let Some(head) = self.head.take() {
            Free { next: RawLink::some(head) }
        } else {
            Free { next: RawLink::none() }
        };
        self.head = Some(mem::transmute(block_ptr));
        self.length += 1;
    }
    /// Pop the head block off of the free list.
    ///
    /// # Returns
    ///   - `Some(*mut u8)` if the free list has blocks left
    ///   - `None` if the free list is empty
    ///
    /// # Unsafe due to
    ///   - `mem::transmute()`
    ///   - Dereferencing a raw pointer
    unsafe fn pop(&mut self) -> Option<*mut u8> {
        self.head.take()
            .map(|head| {
                let popped_block
                    = mem::replace(&mut self.head, head.next.resolve_mut());
                let block_ptr: *mut u8
                    = mem::transmute(popped_block);
                block_ptr
            })
    }

    fn iter<'b>(&'b self) -> FreeListIter<'b> {
        // FreeListIter { current: self.head.map(|c| c.borrow())
        //                             .as_ref()
        //              }
        match self.head {
            Some(ref head) => FreeListIter { current: Some(head) }
          , None           => FreeListIter { current: None }
        }
        // unimplemented!()
    }

    fn iter_mut<'b>(&'b mut self) -> FreeListIterMut<'b> {
        // FreeListIterMut { current: self.head.map(|c| *c ).as_mut() }
        match self.head {
            Some(ref mut head) => FreeListIterMut { current: Some(head) }
          , None               => FreeListIterMut { current: None }
        }
    }
}

struct FreeListIter<'a> {
    current: Option<&'a Free>
}

impl<'a> Iterator for FreeListIter<'a> {
    type Item = &'a Free;

    fn next(&mut self) -> Option<&'a Free> {
        self.current
            .map(|c| {
                self.current = unsafe { c.next.resolve() };
                c
            })
    }
}

struct FreeListIterMut<'a> {
    current: Option<&'a mut Free>
}

impl<'a> Iterator for FreeListIterMut<'a> {
    type Item = &'a mut Free;

    fn next(&mut self) -> Option<&'a mut Free> {
        self.current.take()
            .map(|c| {
                self.current = unsafe { c.next.resolve_mut() };
                c
            })
    }
}

pub struct BuddyHeapAllocator<'a> {
    /// Address of the base of the heap. This must be aligned
    /// on a `MIN_ALIGN` boundary.
    start_addr: *mut u8
  , /// The allocator's free list
    free_lists: &'a mut [FreeList<'a>]
  , /// Number of blocks in the heap (must be a power of 2)
    heap_size: usize
  , /// Minimum block size
    min_block_size: usize
}

impl<'a> BuddyHeapAllocator<'a> {
    pub unsafe fn new( start_addr: *mut u8
                     , free_lists: &'a mut [FreeList<'a>]
                     , heap_size: usize)
                     -> BuddyHeapAllocator<'a>
    {
        let n_free_lists = free_lists.len();

        assert!( !start_addr.is_null()
                , "Heap start address cannot be null." );
        assert!( n_free_lists > 0
               , "Allocator must have at least one free list.");
        assert!( start_addr as usize & (MIN_ALIGN-1) == 0
               , "Heap start address must be aligned on a 4k boundary.");

        let min_block_size = heap_size >> (n_free_lists - 1);

        assert!( heap_size >= min_block_size
               , "Heap must be large enough to contain at least one block.");
        assert!( min_block_size >= mem::size_of::<Free>()
               , "Minimum block size must be large enough to contain \
                  the free block header.");

        let mut heap
            = BuddyHeapAllocator { start_addr: start_addr
                                 , free_lists: free_lists
                                 , heap_size: heap_size
                                 , min_block_size: min_block_size
                                 };
        // TODO: put first head block on appropriately-sized freelist
        heap
    }
}
<|endoftext|>


<commit_before>import ctypes::*;

export libc;
export libc_constants;
export pipe;
export fd_FILE;
export close;
export fclose;
export waitpid;
export getcwd;
export exec_suffix;
export target_os;
export dylib_filename;
export get_exe_path;

// FIXME Refactor into unix_os module or some such. Doesn't
// seem to work right now.

#[link_name = ""]
#[abi = "cdecl"]
native mod libc {
    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
    fn close(fd: fd_t) -> c_int;
    type FILE;
    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
    fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
    fn fclose(f: FILE);
    fn fgetc(f: FILE) -> c_int;
    fn ungetc(c: c_int, f: FILE);
    fn feof(f: FILE) -> c_int;
    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
    fn ftell(f: FILE) -> long;
    type dir;
    fn opendir(d: str::sbuf) -> dir;
    fn closedir(d: dir) -> c_int;
    type dirent;
    fn readdir(d: dir) -> dirent;
    fn getenv(n: str::sbuf) -> str::sbuf;
    fn setenv(n: str::sbuf, v: str::sbuf, overwrite: int) -> int;
    fn unsetenv(n: str::sbuf) -> int;
    fn pipe(buf: *mutable int) -> int;
    fn waitpid(pid: int, &status: int, options: int) -> int;
    fn mkdir(s: str::sbuf, mode: int) -> int;
    fn rmdir(s: str::sbuf) -> int;
}

mod libc_constants {
    const O_RDONLY: c_int   = 0i32;
    const O_WRONLY: c_int   = 1i32;
    const O_RDWR: c_int     = 2i32;
    const O_APPEND: c_int   = 8i32;
    const O_CREAT: c_int    = 512i32;
    const O_EXCL: c_int     = 2048i32;
    const O_TRUNC: c_int    = 1024i32;
    const O_TEXT: c_int     = 0i32;    // nonexistent in darwin libc
    const O_BINARY: c_int   = 0i32;    // nonexistent in darwin libc

    const S_IRUSR: unsigned = 256u32;
    const S_IWUSR: unsigned = 128u32;
}

fn pipe() -> {in: fd_t, out: fd_t} {
    let fds = {mutable in: 0i32, mutable out: 0i32};
    assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32);
    ret {in: fds.in, out: fds.out};
}

fn fd_FILE(fd: fd_t) -> libc::FILE {
    ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
}

fn close(fd: fd_t) -> c_int {
    libc::close(fd)
}

fn fclose(file: libc::FILE) {
    libc::fclose(file)
}

fn waitpid(pid: pid_t) -> i32 {
    let status = 0i32;
    assert (os::libc::waitpid(pid, status, 0i32) != -1i32);
    ret status;
}

#[abi = "cdecl"]
native mod rustrt {
    fn rust_getcwd() -> str;
}

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

#[link_name = ""]
#[abi = "cdecl"]
native mod mac_libc {
    fn _NSGetExecutablePath(buf: str::sbuf,
                            bufsize: *mutable uint32_t) -> c_int;
}

fn exec_suffix() -> str { ret ""; }

fn target_os() -> str { ret "macos"; }

fn dylib_filename(base: str) -> str { ret "lib" + base + ".dylib"; }

fn get_exe_path() -> option::t<fs::path> {
    // FIXME: This doesn't handle the case where the buffer is too small
    let bufsize = 1023u32;
    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize as uint));
    ret str::as_buf(path, { |path_buf|
        if mac_libc::_NSGetExecutablePath(path_buf,
                                          ptr::mut_addr_of(bufsize)) == 0i32 {
            option::some(fs::dirname(path) + fs::path_sep())
        } else {
            option::none
        }
    });
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>stdlib: Fix some busted macos libc decls<commit_after>import ctypes::*;

export libc;
export libc_constants;
export pipe;
export fd_FILE;
export close;
export fclose;
export waitpid;
export getcwd;
export exec_suffix;
export target_os;
export dylib_filename;
export get_exe_path;

// FIXME Refactor into unix_os module or some such. Doesn't
// seem to work right now.

#[link_name = ""]
#[abi = "cdecl"]
native mod libc {
    fn read(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn write(fd: fd_t, buf: *u8, count: size_t) -> ssize_t;
    fn fread(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn fwrite(buf: *u8, size: size_t, n: size_t, f: libc::FILE) -> size_t;
    fn open(s: str::sbuf, flags: c_int, mode: unsigned) -> fd_t;
    fn close(fd: fd_t) -> c_int;
    type FILE;
    fn fopen(path: str::sbuf, mode: str::sbuf) -> FILE;
    fn fdopen(fd: fd_t, mode: str::sbuf) -> FILE;
    fn fclose(f: FILE);
    fn fgetc(f: FILE) -> c_int;
    fn ungetc(c: c_int, f: FILE);
    fn feof(f: FILE) -> c_int;
    fn fseek(f: FILE, offset: long, whence: c_int) -> c_int;
    fn ftell(f: FILE) -> long;
    type dir;
    fn opendir(d: str::sbuf) -> dir;
    fn closedir(d: dir) -> c_int;
    type dirent;
    fn readdir(d: dir) -> dirent;
    fn getenv(n: str::sbuf) -> str::sbuf;
    fn setenv(n: str::sbuf, v: str::sbuf, overwrite: c_int) -> c_int;
    fn unsetenv(n: str::sbuf) -> c_int;
    fn pipe(buf: *mutable c_int) -> c_int;
    fn waitpid(pid: int, &status: c_int, options: c_int) -> c_int;
    fn mkdir(s: str::sbuf, mode: c_int) -> c_int;
    fn rmdir(s: str::sbuf) -> c_int;
}

mod libc_constants {
    const O_RDONLY: c_int   = 0i32;
    const O_WRONLY: c_int   = 1i32;
    const O_RDWR: c_int     = 2i32;
    const O_APPEND: c_int   = 8i32;
    const O_CREAT: c_int    = 512i32;
    const O_EXCL: c_int     = 2048i32;
    const O_TRUNC: c_int    = 1024i32;
    const O_TEXT: c_int     = 0i32;    // nonexistent in darwin libc
    const O_BINARY: c_int   = 0i32;    // nonexistent in darwin libc

    const S_IRUSR: unsigned = 256u32;
    const S_IWUSR: unsigned = 128u32;
}

fn pipe() -> {in: fd_t, out: fd_t} {
    let fds = {mutable in: 0i32, mutable out: 0i32};
    assert (os::libc::pipe(ptr::mut_addr_of(fds.in)) == 0i32);
    ret {in: fds.in, out: fds.out};
}

fn fd_FILE(fd: fd_t) -> libc::FILE {
    ret str::as_buf("r", {|modebuf| libc::fdopen(fd, modebuf) });
}

fn close(fd: fd_t) -> c_int {
    libc::close(fd)
}

fn fclose(file: libc::FILE) {
    libc::fclose(file)
}

fn waitpid(pid: pid_t) -> i32 {
    let status = 0i32;
    assert (os::libc::waitpid(pid, status, 0i32) != -1i32);
    ret status;
}

#[abi = "cdecl"]
native mod rustrt {
    fn rust_getcwd() -> str;
}

fn getcwd() -> str { ret rustrt::rust_getcwd(); }

#[link_name = ""]
#[abi = "cdecl"]
native mod mac_libc {
    fn _NSGetExecutablePath(buf: str::sbuf,
                            bufsize: *mutable uint32_t) -> c_int;
}

fn exec_suffix() -> str { ret ""; }

fn target_os() -> str { ret "macos"; }

fn dylib_filename(base: str) -> str { ret "lib" + base + ".dylib"; }

fn get_exe_path() -> option::t<fs::path> {
    // FIXME: This doesn't handle the case where the buffer is too small
    let bufsize = 1023u32;
    let path = str::unsafe_from_bytes(vec::init_elt(0u8, bufsize as uint));
    ret str::as_buf(path, { |path_buf|
        if mac_libc::_NSGetExecutablePath(path_buf,
                                          ptr::mut_addr_of(bufsize)) == 0i32 {
            option::some(fs::dirname(path) + fs::path_sep())
        } else {
            option::none
        }
    });
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>//! Tool for generating on-chip data.

#[cfg(test)]
extern crate assert;

#[macro_use]
extern crate log;

extern crate configuration;
extern crate fractal;
extern crate probability;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate temperature;
extern crate threed_ice;

#[macro_use]
mod macros;

mod result;

pub mod platform;
pub mod schedule;
pub mod system;
pub mod traffic;
pub mod workload;

pub use result::{Error, Result};

/// A configuration.
pub type Config = configuration::Tree;

/// A source of randomness.
pub type Source = random::Default;

mod math {
    #[link_name = "m"]
    extern {
        fn nextafter(x: f64, y: f64) -> f64;
    }

    #[inline]
    pub fn next_after(x: f64) -> f64 {
        use std::f64::INFINITY;
        unsafe { nextafter(x, INFINITY) }
    }
}
<commit_msg>A cosmetic change<commit_after>//! Tool for generating on-chip data.

extern crate configuration;
extern crate fractal;
extern crate probability;
extern crate random;
extern crate sql;
extern crate sqlite;
extern crate temperature;
extern crate threed_ice;

#[cfg(test)]
extern crate assert;

#[macro_use]
extern crate log;

#[macro_use]
mod macros;

mod result;

pub mod platform;
pub mod schedule;
pub mod system;
pub mod traffic;
pub mod workload;

pub use result::{Error, Result};

/// A configuration.
pub type Config = configuration::Tree;

/// A source of randomness.
pub type Source = random::Default;

mod math {
    #[link_name = "m"]
    extern {
        fn nextafter(x: f64, y: f64) -> f64;
    }

    #[inline]
    pub fn next_after(x: f64) -> f64 {
        use std::f64::INFINITY;
        unsafe { nextafter(x, INFINITY) }
    }
}
<|endoftext|>


<commit_before>use bindings::{
	jit_value_t,
	jit_value_get_type,
	jit_value_get_function
};
use function::Function;
use types::Type;
use util::NativeRef;
#[deriving(Clone)]
/// A Value that is being JIT compiled
native_ref!(Value, _value, jit_value_t)
impl Value {
	/// Get the type of the value
	pub fn get_type(&self) -> Type {
		unsafe {
			let ty = jit_value_get_type(self.as_ptr());
			NativeRef::from_ptr(ty)
		}
	}
	/// Get the function which owns this value
	pub fn get_function(&self) -> Function {
		unsafe {
			NativeRef::from_ptr(jit_value_get_function(self.as_ptr()))
		}
	}
}
<commit_msg>Add `get_context` to value<commit_after>use bindings::{
	jit_value_t,
	jit_value_get_context,
	jit_value_get_type,
	jit_value_get_function
};
use context::Context;
use function::Function;
use types::Type;
use util::NativeRef;
#[deriving(Clone)]
/// A Value that is being JIT compiled
native_ref!(Value, _value, jit_value_t)
impl Value {
	/// Get the type of the value
	pub fn get_type(&self) -> Type {
		unsafe {
			let ty = jit_value_get_type(self.as_ptr());
			NativeRef::from_ptr(ty)
		}
	}
	/// Get the function which owns this value
	pub fn get_function(&self) -> Function {
		unsafe {
			NativeRef::from_ptr(jit_value_get_function(self.as_ptr()))
		}
	}
	/// Get the context which this value belongs to
	pub fn get_context(&self) -> Context {
		unsafe {
			NativeRef::from_ptr(jit_value_get_context(self.as_ptr()))
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(discriminant_value)]
#![feature(i128_type)]
#![feature(libc)]
#![feature(never_type)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(discriminant_value)]
#![feature(sort_unstable)]
#![feature(trace_macros)]

#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(rustc_private))]
#![cfg_attr(stage0, feature(staged_api))]
#![cfg_attr(stage0, feature(loop_break_value))]

#![recursion_limit="128"]

extern crate arena;
extern crate core;
extern crate fmt_macros;
extern crate getopts;
extern crate graphviz;
extern crate libc;
extern crate owning_ref;
extern crate rustc_back;
extern crate rustc_data_structures;
extern crate serialize;
extern crate rustc_const_math;
extern crate rustc_errors as errors;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

#[macro_use]
mod macros;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod ich;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod expr_use_visitor;
    pub mod const_val;
    pub mod cstore;
    pub mod dataflow;
    pub mod dead;
    pub mod dependency_format;
    pub mod effect;
    pub mod entry;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod weak_lang_items;
}

pub mod mir;
pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod fs;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<commit_msg>increase macro recursion limit<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![crate_name = "rustc"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(discriminant_value)]
#![feature(i128_type)]
#![feature(libc)]
#![feature(never_type)]
#![feature(nonzero)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(discriminant_value)]
#![feature(sort_unstable)]
#![feature(trace_macros)]

#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
#![cfg_attr(stage0, feature(rustc_private))]
#![cfg_attr(stage0, feature(staged_api))]
#![cfg_attr(stage0, feature(loop_break_value))]

#![recursion_limit="192"]

extern crate arena;
extern crate core;
extern crate fmt_macros;
extern crate getopts;
extern crate graphviz;
extern crate libc;
extern crate owning_ref;
extern crate rustc_back;
extern crate rustc_data_structures;
extern crate serialize;
extern crate rustc_const_math;
extern crate rustc_errors as errors;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
#[macro_use] #[no_link] extern crate rustc_bitflags;

extern crate serialize as rustc_serialize; // used by deriving

#[macro_use]
mod macros;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;

pub mod cfg;
pub mod dep_graph;
pub mod hir;
pub mod ich;
pub mod infer;
pub mod lint;

pub mod middle {
    pub mod expr_use_visitor;
    pub mod const_val;
    pub mod cstore;
    pub mod dataflow;
    pub mod dead;
    pub mod dependency_format;
    pub mod effect;
    pub mod entry;
    pub mod free_region;
    pub mod intrinsicck;
    pub mod lang_items;
    pub mod liveness;
    pub mod mem_categorization;
    pub mod privacy;
    pub mod reachable;
    pub mod region;
    pub mod recursion_limit;
    pub mod resolve_lifetime;
    pub mod stability;
    pub mod weak_lang_items;
}

pub mod mir;
pub mod session;
pub mod traits;
pub mod ty;

pub mod util {
    pub mod common;
    pub mod ppaux;
    pub mod nodemap;
    pub mod fs;
}

// A private module so that macro-expanded idents like
// `::rustc::lint::Lint` will also work in `rustc` itself.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod rustc {
    pub use lint;
}

// FIXME(#27438): right now the unit tests of librustc don't refer to any actual
//                functions generated in librustc_data_structures (all
//                references are through generic functions), but statics are
//                referenced from time to time. Due to this bug we won't
//                actually correctly link in the statics unless we also
//                reference a function, so be sure to reference a dummy
//                function.
#[test]
fn noop() {
    rustc_data_structures::__noop_fix_for_27438();
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc, DIAGNOSTICS }
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified.
//! The compiler may link to a version of [jemalloc] on some platforms,
//! but this is not guaranteed.
//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
//! to use the [`System`] by default.
//!
//! [jemalloc]: https://github.com/jemalloc/jemalloc
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallacator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![stable(feature = "alloc_module", since = "1.28.0")]

use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
use sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[doc(inline)]
pub use alloc_system::System;

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() {
        default_alloc_error_hook
    } else {
        unsafe { mem::transmute(hook) }
    }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[lang = "oom"]
#[unstable(feature = "alloc_internals", issue = "0")]
pub extern fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) = if hook.is_null() {
        default_alloc_error_hook
    } else {
        unsafe { mem::transmute(hook) }
    };
    hook(layout);
    unsafe { ::sys::abort_internal(); }
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "0")]
pub mod __default_lib_allocator {
    use super::{System, Layout, GlobalAlloc};
    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc(layout)
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
                                       old_size: usize,
                                       align: usize,
                                       new_size: usize) -> *mut u8 {
        let old_layout = Layout::from_size_align_unchecked(old_size, align);
        System.realloc(ptr, old_layout, new_size)
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc_zeroed(layout)
    }
}
<commit_msg>Fix inconsequential typo in GlobalAlloc doc example<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Memory allocation APIs
//!
//! In a given program, the standard library has one “global” memory allocator
//! that is used for example by `Box<T>` and `Vec<T>`.
//!
//! Currently the default global allocator is unspecified.
//! The compiler may link to a version of [jemalloc] on some platforms,
//! but this is not guaranteed.
//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
//! to use the [`System`] by default.
//!
//! [jemalloc]: https://github.com/jemalloc/jemalloc
//! [`System`]: struct.System.html
//!
//! # The `#[global_allocator]` attribute
//!
//! This attribute allows configuring the choice of global allocator.
//! You can use this to implement a completely custom global allocator
//! to route all default allocation requests to a custom object.
//!
//! ```rust
//! use std::alloc::{GlobalAlloc, System, Layout};
//!
//! struct MyAllocator;
//!
//! unsafe impl GlobalAlloc for MyAllocator {
//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
//!         System.alloc(layout)
//!     }
//!
//!     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
//!         System.dealloc(ptr, layout)
//!     }
//! }
//!
//! #[global_allocator]
//! static GLOBAL: MyAllocator = MyAllocator;
//!
//! fn main() {
//!     // This `Vec` will allocate memory through `GLOBAL` above
//!     let mut v = Vec::new();
//!     v.push(1);
//! }
//! ```
//!
//! The attribute is used on a `static` item whose type implements the
//! [`GlobalAlloc`] trait. This type can be provided by an external library:
//!
//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
//!
//! ```rust,ignore (demonstrates crates.io usage)
//! extern crate jemallocator;
//!
//! use jemallocator::Jemalloc;
//!
//! #[global_allocator]
//! static GLOBAL: Jemalloc = Jemalloc;
//!
//! fn main() {}
//! ```
//!
//! The `#[global_allocator]` can only be used once in a crate
//! or its recursive dependencies.

#![stable(feature = "alloc_module", since = "1.28.0")]

use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
use sys_common::util::dumb_print;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use alloc_crate::alloc::*;

#[stable(feature = "alloc_system_type", since = "1.28.0")]
#[doc(inline)]
pub use alloc_system::System;

static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());

/// Registers a custom allocation error hook, replacing any that was previously registered.
///
/// The allocation error hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The allocation error hook is a global resource.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn set_alloc_error_hook(hook: fn(Layout)) {
    HOOK.store(hook as *mut (), Ordering::SeqCst);
}

/// Unregisters the current allocation error hook, returning it.
///
/// *See also the function [`set_alloc_error_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
#[unstable(feature = "alloc_error_hook", issue = "51245")]
pub fn take_alloc_error_hook() -> fn(Layout) {
    let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
    if hook.is_null() {
        default_alloc_error_hook
    } else {
        unsafe { mem::transmute(hook) }
    }
}

fn default_alloc_error_hook(layout: Layout) {
    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}

#[cfg(not(test))]
#[doc(hidden)]
#[lang = "oom"]
#[unstable(feature = "alloc_internals", issue = "0")]
pub extern fn rust_oom(layout: Layout) -> ! {
    let hook = HOOK.load(Ordering::SeqCst);
    let hook: fn(Layout) = if hook.is_null() {
        default_alloc_error_hook
    } else {
        unsafe { mem::transmute(hook) }
    };
    hook(layout);
    unsafe { ::sys::abort_internal(); }
}

#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "0")]
pub mod __default_lib_allocator {
    use super::{System, Layout, GlobalAlloc};
    // for symbol names src/librustc/middle/allocator.rs
    // for signatures src/librustc_allocator/lib.rs

    // linkage directives are provided as part of the current compiler allocator
    // ABI

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc(layout)
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                       size: usize,
                                       align: usize) {
        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
                                       old_size: usize,
                                       align: usize,
                                       new_size: usize) -> *mut u8 {
        let old_layout = Layout::from_size_align_unchecked(old_size, align);
        System.realloc(ptr, old_layout, new_size)
    }

    #[no_mangle]
    #[rustc_std_internal_symbol]
    pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
        let layout = Layout::from_size_align_unchecked(size, align);
        System.alloc_zeroed(layout)
    }
}
<|endoftext|>