<commit_before>/*!

Sendable hash maps.  Very much a work in progress.

*/

/**
 * A function that returns a hash of a value
 *
 * The hash should concentrate entropy in the lower bits.
 */
type HashFn<K> = pure fn~(K) -> uint;
type EqFn<K> = pure fn~(K, K) -> bool;

/// Open addressing with linear probing.
mod linear {
    export LinearMap, linear_map, linear_map_with_capacity, public_methods;

    const initial_capacity: uint = 32u; // 2^5
    type Bucket<K,V> = {hash: uint, key: K, value: V};
    enum LinearMap<K,V> {
        LinearMap_({
            hashfn: pure fn~(x: &K) -> uint,
            eqfn: pure fn~(x: &K, y: &K) -> bool,
            resize_at: uint,
            size: uint,
            buckets: ~[option<Bucket<K,V>>]})
    }

    // FIXME(#2979) -- with #2979 we could rewrite found_entry
    // to have type option<&bucket<K,V>> which would be nifty
    enum SearchResult {
        FoundEntry(uint), FoundHole(uint), TableFull
    }

    fn resize_at(capacity: uint) -> uint {
        ((capacity as float) * 3. / 4.) as uint
    }

    fn linear_map<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {

        linear_map_with_capacity(hashfn, eqfn, 32)
    }

    fn linear_map_with_capacity<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool,
        initial_capacity: uint) -> LinearMap<K,V> {

        LinearMap_({
            hashfn: hashfn,
            eqfn: eqfn,
            resize_at: resize_at(initial_capacity),
            size: 0,
            buckets: vec::from_fn(initial_capacity, |_i| none)})
    }

    // FIXME(#2979) would allow us to use region type for k
    unsafe fn borrow<K>(&&k: K) -> &K {
        let p: *K = ptr::addr_of(k);
        unsafe::reinterpret_cast(p)
    }

    priv impl<K, V> &const LinearMap<K,V> {
        #[inline(always)]
        pure fn to_bucket(h: uint) -> uint {
            // FIXME(#3041) borrow a more sophisticated technique here from
            // Gecko, for example borrowing from Knuth, as Eich so
            // colorfully argues for here:
            // https://bugzilla.mozilla.org/show_bug.cgi?id=743107#c22
            h % self.buckets.len()
        }

        #[inline(always)]
        pure fn next_bucket(idx: uint, len_buckets: uint) -> uint {
            let n = (idx + 1) % len_buckets;
            unsafe{ // argh. log not considered pure.
                debug!{"next_bucket(%?, %?) = %?", idx, len_buckets, n};
            }
            return n;
        }

        #[inline(always)]
        pure fn bucket_sequence(hash: uint, op: fn(uint) -> bool) -> uint {
            let start_idx = self.to_bucket(hash);
            let len_buckets = self.buckets.len();
            let mut idx = start_idx;
            loop {
                if !op(idx) {
                    return idx;
                }
                idx = self.next_bucket(idx, len_buckets);
                if idx == start_idx {
                    return start_idx;
                }
            }
        }

        #[inline(always)]
        pure fn bucket_for_key(
            buckets: &[option<Bucket<K,V>>],
            k: &K) -> SearchResult {

            let hash = self.hashfn(k);
            self.bucket_for_key_with_hash(buckets, hash, k)
        }

        #[inline(always)]
        pure fn bucket_for_key_with_hash(
            buckets: &[option<Bucket<K,V>>],
            hash: uint,
            k: &K) -> SearchResult {

            let _ = for self.bucket_sequence(hash) |i| {
                match buckets[i] {
                  some(bkt) => if bkt.hash == hash && self.eqfn(k, &bkt.key) {
                    return FoundEntry(i);
                  },
                  none => return FoundHole(i)
                }
            };
            return TableFull;
        }
    }

    priv impl<K,V> &mut LinearMap<K,V> {
        /// Expands the capacity of the array and re-inserts each
        /// of the existing buckets.
        fn expand() {
            let old_capacity = self.buckets.len();
            let new_capacity = old_capacity * 2;
            self.resize_at = ((new_capacity as float) * 3.0 / 4.0) as uint;

            let mut old_buckets = vec::from_fn(new_capacity, |_i| none);
            self.buckets <-> old_buckets;

            for uint::range(0, old_capacity) |i| {
                let mut bucket = none;
                bucket <-> old_buckets[i];
                if bucket.is_some() {
                    self.insert_bucket(bucket);
                }
            }
        }

        fn insert_bucket(+bucket: option<Bucket<K,V>>) {
            let {hash, key, value} <- option::unwrap(bucket);
            let _ = self.insert_internal(hash, key, value);
        }

        /// Inserts the key value pair into the buckets.
        /// Assumes that there will be a bucket.
        /// True if there was no previous entry with that key
        fn insert_internal(hash: uint, +k: K, +v: V) -> bool {
            match self.bucket_for_key_with_hash(self.buckets, hash,
                                              unsafe{borrow(k)}) {
              TableFull => {fail ~"Internal logic error";}
              FoundHole(idx) => {
                debug!{"insert fresh (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                self.size += 1;
                return true;
              }
              FoundEntry(idx) => {
                debug!{"insert overwrite (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                return false;
              }
            }
        }
    }

    impl<K,V> &mut LinearMap<K,V> {
        fn insert(+k: K, +v: V) -> bool {
            if self.size >= self.resize_at {
                // n.b.: We could also do this after searching, so
                // that we do not resize if this call to insert is
                // simply going to update a key in place.  My sense
                // though is that it's worse to have to search through
                // buckets to find the right spot twice than to just
                // resize in this corner case.
                self.expand();
            }

            let hash = self.hashfn(unsafe{borrow(k)});
            self.insert_internal(hash, k, v)
        }

        fn remove(k: &K) -> bool {
            // Removing from an open-addressed hashtable
            // is, well, painful.  The problem is that
            // the entry may lie on the probe path for other
            // entries, so removing it would make you think that
            // those probe paths are empty.
            //
            // To address this we basically have to keep walking,
            // re-inserting entries we find until we reach an empty
            // bucket.  We know we will eventually reach one because
            // we insert one ourselves at the beginning (the removed
            // entry).
            //
            // I found this explanation elucidating:
            // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf

            let mut idx = match self.bucket_for_key(self.buckets, k) {
              TableFull | FoundHole(_) => {
                return false;
              }
              FoundEntry(idx) => {
                idx
              }
            };

            let len_buckets = self.buckets.len();
            self.buckets[idx] = none;
            idx = self.next_bucket(idx, len_buckets);
            while self.buckets[idx].is_some() {
                let mut bucket = none;
                bucket <-> self.buckets[idx];
                self.insert_bucket(bucket);
                idx = self.next_bucket(idx, len_buckets);
            }
            self.size -= 1;
            return true;
        }
    }

    priv impl<K,V> &LinearMap<K,V> {
        fn search(hash: uint, op: fn(x: &option<Bucket<K,V>>) -> bool) {
            let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
        }
    }

    impl<K,V> &const LinearMap<K,V> {
        pure fn len() -> uint {
            self.size
        }

        pure fn is_empty() -> bool {
            self.len() == 0
        }

        fn contains_key(k: &K) -> bool {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(_) => {true}
              TableFull | FoundHole(_) => {false}
            }
        }
    }

    impl<K,V: copy> &const LinearMap<K,V> {
        fn find(k: &K) -> option<V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(bkt) => {some(copy bkt.value)}
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }

        fn get(k: &K) -> V {
            let value = self.find(k);
            if value.is_none() {
                fail fmt!{"No entry found for key: %?", k};
            }
            option::unwrap(value)
        }

    }

    impl<K,V> &LinearMap<K,V> {
        /*
        FIXME --- #2979 must be fixed to typecheck this
        fn find_ptr(k: K) -> option<&V> {
            //XXX this should not type check as written, but it should
            //be *possible* to typecheck it...
            self.with_ptr(k, |v| v)
        }
        */

        fn each_ref(blk: fn(k: &K, v: &V) -> bool) {
            for vec::each(self.buckets) |slot| {
                let mut broke = false;
                do slot.iter |bucket| {
                    if !blk(&bucket.key, &bucket.value) {
                        broke = true; // FIXME(#3064) just write "break;"
                    }
                }
                if broke { break; }
            }
        }
        fn each_key_ref(blk: fn(k: &K) -> bool) {
            self.each_ref(|k, _v| blk(k))
        }
        fn each_value_ref(blk: fn(v: &V) -> bool) {
            self.each_ref(|_k, v| blk(v))
        }
    }

    impl<K: copy, V: copy> &LinearMap<K,V> {
        fn each(blk: fn(+K,+V) -> bool) {
            self.each_ref(|k,v| blk(copy *k, copy *v));
        }
    }
    impl<K: copy, V> &LinearMap<K,V> {
        fn each_key(blk: fn(+K) -> bool) {
            self.each_key_ref(|k| blk(copy *k));
        }
    }
    impl<K, V: copy> &LinearMap<K,V> {
        fn each_value(blk: fn(+V) -> bool) {
            self.each_value_ref(|v| blk(copy *v));
        }
    }
}

#[test]
mod test {

    import linear::{LinearMap, linear_map};

    pure fn uint_hash(x: &uint) -> uint { *x }
    pure fn uint_eq(x: &uint, y: &uint) -> bool { *x == *y }

    fn int_linear_map<V>() -> LinearMap<uint,V> {
        return linear_map(uint_hash, uint_eq);
    }

    #[test]
    fn inserts() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.insert(2, 4);
        assert m.get(&1) == 2;
        assert m.get(&2) == 4;
    }

    #[test]
    fn overwrite() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.get(&1) == 2;
        assert !m.insert(1, 3);
        assert m.get(&1) == 3;
    }

    #[test]
    fn conflicts() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
        assert m.get(&1) == 2;
    }

    #[test]
    fn conflict_remove() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.remove(&1);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
    }

    #[test]
    fn empty() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert !m.is_empty();
        assert m.remove(&1);
        assert m.is_empty();
    }

    #[test]
    fn iterate() {
        let mut m = linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        for uint::range(0, 32) |i| {
            assert (&mut m).insert(i, i*2);
        }
        let mut observed = 0;
        for (&m).each |k, v| {
            assert v == k*2;
            observed |= (1 << k);
        }
        assert observed == 0xFFFF_FFFF;
    }
}
<commit_msg>remove some FIXMEd code as the relevant issue is fixed<commit_after>/*!

Sendable hash maps.  Very much a work in progress.

*/

/**
 * A function that returns a hash of a value
 *
 * The hash should concentrate entropy in the lower bits.
 */
type HashFn<K> = pure fn~(K) -> uint;
type EqFn<K> = pure fn~(K, K) -> bool;

/// Open addressing with linear probing.
mod linear {
    export LinearMap, linear_map, linear_map_with_capacity, public_methods;

    const initial_capacity: uint = 32u; // 2^5
    type Bucket<K,V> = {hash: uint, key: K, value: V};
    enum LinearMap<K,V> {
        LinearMap_({
            hashfn: pure fn~(x: &K) -> uint,
            eqfn: pure fn~(x: &K, y: &K) -> bool,
            resize_at: uint,
            size: uint,
            buckets: ~[option<Bucket<K,V>>]})
    }

    // FIXME(#2979) -- with #2979 we could rewrite found_entry
    // to have type option<&bucket<K,V>> which would be nifty
    enum SearchResult {
        FoundEntry(uint), FoundHole(uint), TableFull
    }

    fn resize_at(capacity: uint) -> uint {
        ((capacity as float) * 3. / 4.) as uint
    }

    fn linear_map<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool) -> LinearMap<K,V> {

        linear_map_with_capacity(hashfn, eqfn, 32)
    }

    fn linear_map_with_capacity<K,V>(
        +hashfn: pure fn~(x: &K) -> uint,
        +eqfn: pure fn~(x: &K, y: &K) -> bool,
        initial_capacity: uint) -> LinearMap<K,V> {

        LinearMap_({
            hashfn: hashfn,
            eqfn: eqfn,
            resize_at: resize_at(initial_capacity),
            size: 0,
            buckets: vec::from_fn(initial_capacity, |_i| none)})
    }

    priv impl<K, V> &const LinearMap<K,V> {
        #[inline(always)]
        pure fn to_bucket(h: uint) -> uint {
            // FIXME(#3041) borrow a more sophisticated technique here from
            // Gecko, for example borrowing from Knuth, as Eich so
            // colorfully argues for here:
            // https://bugzilla.mozilla.org/show_bug.cgi?id=743107#c22
            h % self.buckets.len()
        }

        #[inline(always)]
        pure fn next_bucket(idx: uint, len_buckets: uint) -> uint {
            let n = (idx + 1) % len_buckets;
            unsafe{ // argh. log not considered pure.
                debug!{"next_bucket(%?, %?) = %?", idx, len_buckets, n};
            }
            return n;
        }

        #[inline(always)]
        pure fn bucket_sequence(hash: uint, op: fn(uint) -> bool) -> uint {
            let start_idx = self.to_bucket(hash);
            let len_buckets = self.buckets.len();
            let mut idx = start_idx;
            loop {
                if !op(idx) {
                    return idx;
                }
                idx = self.next_bucket(idx, len_buckets);
                if idx == start_idx {
                    return start_idx;
                }
            }
        }

        #[inline(always)]
        pure fn bucket_for_key(
            buckets: &[option<Bucket<K,V>>],
            k: &K) -> SearchResult {

            let hash = self.hashfn(k);
            self.bucket_for_key_with_hash(buckets, hash, k)
        }

        #[inline(always)]
        pure fn bucket_for_key_with_hash(
            buckets: &[option<Bucket<K,V>>],
            hash: uint,
            k: &K) -> SearchResult {

            let _ = for self.bucket_sequence(hash) |i| {
                match buckets[i] {
                  some(bkt) => if bkt.hash == hash && self.eqfn(k, &bkt.key) {
                    return FoundEntry(i);
                  },
                  none => return FoundHole(i)
                }
            };
            return TableFull;
        }
    }

    priv impl<K,V> &mut LinearMap<K,V> {
        /// Expands the capacity of the array and re-inserts each
        /// of the existing buckets.
        fn expand() {
            let old_capacity = self.buckets.len();
            let new_capacity = old_capacity * 2;
            self.resize_at = ((new_capacity as float) * 3.0 / 4.0) as uint;

            let mut old_buckets = vec::from_fn(new_capacity, |_i| none);
            self.buckets <-> old_buckets;

            for uint::range(0, old_capacity) |i| {
                let mut bucket = none;
                bucket <-> old_buckets[i];
                if bucket.is_some() {
                    self.insert_bucket(bucket);
                }
            }
        }

        fn insert_bucket(+bucket: option<Bucket<K,V>>) {
            let {hash, key, value} <- option::unwrap(bucket);
            let _ = self.insert_internal(hash, key, value);
        }

        /// Inserts the key value pair into the buckets.
        /// Assumes that there will be a bucket.
        /// True if there was no previous entry with that key
        fn insert_internal(hash: uint, +k: K, +v: V) -> bool {
            match self.bucket_for_key_with_hash(self.buckets, hash, &k) {
              TableFull => {fail ~"Internal logic error";}
              FoundHole(idx) => {
                debug!{"insert fresh (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                self.size += 1;
                return true;
              }
              FoundEntry(idx) => {
                debug!{"insert overwrite (%?->%?) at idx %?, hash %?",
                       k, v, idx, hash};
                self.buckets[idx] = some({hash: hash, key: k, value: v});
                return false;
              }
            }
        }
    }

    impl<K,V> &mut LinearMap<K,V> {
        fn insert(+k: K, +v: V) -> bool {
            if self.size >= self.resize_at {
                // n.b.: We could also do this after searching, so
                // that we do not resize if this call to insert is
                // simply going to update a key in place.  My sense
                // though is that it's worse to have to search through
                // buckets to find the right spot twice than to just
                // resize in this corner case.
                self.expand();
            }

            let hash = self.hashfn(&k);
            self.insert_internal(hash, k, v)
        }

        fn remove(k: &K) -> bool {
            // Removing from an open-addressed hashtable
            // is, well, painful.  The problem is that
            // the entry may lie on the probe path for other
            // entries, so removing it would make you think that
            // those probe paths are empty.
            //
            // To address this we basically have to keep walking,
            // re-inserting entries we find until we reach an empty
            // bucket.  We know we will eventually reach one because
            // we insert one ourselves at the beginning (the removed
            // entry).
            //
            // I found this explanation elucidating:
            // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf

            let mut idx = match self.bucket_for_key(self.buckets, k) {
              TableFull | FoundHole(_) => {
                return false;
              }
              FoundEntry(idx) => {
                idx
              }
            };

            let len_buckets = self.buckets.len();
            self.buckets[idx] = none;
            idx = self.next_bucket(idx, len_buckets);
            while self.buckets[idx].is_some() {
                let mut bucket = none;
                bucket <-> self.buckets[idx];
                self.insert_bucket(bucket);
                idx = self.next_bucket(idx, len_buckets);
            }
            self.size -= 1;
            return true;
        }
    }

    priv impl<K,V> &LinearMap<K,V> {
        fn search(hash: uint, op: fn(x: &option<Bucket<K,V>>) -> bool) {
            let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i]));
        }
    }

    impl<K,V> &const LinearMap<K,V> {
        pure fn len() -> uint {
            self.size
        }

        pure fn is_empty() -> bool {
            self.len() == 0
        }

        fn contains_key(k: &K) -> bool {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(_) => {true}
              TableFull | FoundHole(_) => {false}
            }
        }
    }

    impl<K,V: copy> &const LinearMap<K,V> {
        fn find(k: &K) -> option<V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(bkt) => {some(copy bkt.value)}
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }

        fn get(k: &K) -> V {
            let value = self.find(k);
            if value.is_none() {
                fail fmt!{"No entry found for key: %?", k};
            }
            option::unwrap(value)
        }

    }

    impl<K,V> &LinearMap<K,V> {
        /*
        FIXME(#3148)--region inference fails to capture needed deps

        fn find_ref(k: &K) -> option<&self/V> {
            match self.bucket_for_key(self.buckets, k) {
              FoundEntry(idx) => {
                match check self.buckets[idx] {
                  some(ref bkt) => some(&bkt.value)
                }
              }
              TableFull | FoundHole(_) => {
                none
              }
            }
        }
        */

        fn each_ref(blk: fn(k: &K, v: &V) -> bool) {
            for vec::each(self.buckets) |slot| {
                let mut broke = false;
                do slot.iter |bucket| {
                    if !blk(&bucket.key, &bucket.value) {
                        broke = true; // FIXME(#3064) just write "break;"
                    }
                }
                if broke { break; }
            }
        }
        fn each_key_ref(blk: fn(k: &K) -> bool) {
            self.each_ref(|k, _v| blk(k))
        }
        fn each_value_ref(blk: fn(v: &V) -> bool) {
            self.each_ref(|_k, v| blk(v))
        }
    }

    impl<K: copy, V: copy> &LinearMap<K,V> {
        fn each(blk: fn(+K,+V) -> bool) {
            self.each_ref(|k,v| blk(copy *k, copy *v));
        }
    }
    impl<K: copy, V> &LinearMap<K,V> {
        fn each_key(blk: fn(+K) -> bool) {
            self.each_key_ref(|k| blk(copy *k));
        }
    }
    impl<K, V: copy> &LinearMap<K,V> {
        fn each_value(blk: fn(+V) -> bool) {
            self.each_value_ref(|v| blk(copy *v));
        }
    }
}

#[test]
mod test {

    import linear::{LinearMap, linear_map};

    pure fn uint_hash(x: &uint) -> uint { *x }
    pure fn uint_eq(x: &uint, y: &uint) -> bool { *x == *y }

    fn int_linear_map<V>() -> LinearMap<uint,V> {
        return linear_map(uint_hash, uint_eq);
    }

    #[test]
    fn inserts() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.insert(2, 4);
        assert m.get(&1) == 2;
        assert m.get(&2) == 4;
    }

    #[test]
    fn overwrite() {
        let mut m = ~int_linear_map();
        assert m.insert(1, 2);
        assert m.get(&1) == 2;
        assert !m.insert(1, 3);
        assert m.get(&1) == 3;
    }

    #[test]
    fn conflicts() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
        assert m.get(&1) == 2;
    }

    #[test]
    fn conflict_remove() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert m.insert(5, 3);
        assert m.insert(9, 4);
        assert m.remove(&1);
        assert m.get(&9) == 4;
        assert m.get(&5) == 3;
    }

    #[test]
    fn empty() {
        let mut m = ~linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        assert m.insert(1, 2);
        assert !m.is_empty();
        assert m.remove(&1);
        assert m.is_empty();
    }

    #[test]
    fn iterate() {
        let mut m = linear::linear_map_with_capacity(uint_hash, uint_eq, 4);
        for uint::range(0, 32) |i| {
            assert (&mut m).insert(i, i*2);
        }
        let mut observed = 0;
        for (&m).each |k, v| {
            assert v == k*2;
            observed |= (1 << k);
        }
        assert observed == 0xFFFF_FFFF;
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::{uint32_t, c_void, c_int};

extern crate errno;
use self::errno::errno;

use std::str;

// Since we cannot access C macros for constants from Rust - I have had to redefine this, based on Apple's source code
// See http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c
// buffersize must be more than PROC_PIDPATHINFO_SIZE
// buffersize must be less than PROC_PIDPATHINFO_MAXSIZE
//
// See http://opensource.apple.com//source/xnu/xnu-1456.1.26/bsd/sys/proc_info.h
// #define PROC_PIDPATHINFO_SIZE		(MAXPATHLEN)
// #define PROC_PIDPATHINFO_MAXSIZE	(4*MAXPATHLEN)
// in http://opensource.apple.com//source/xnu/xnu-1504.7.4/bsd/sys/param.h
// #define	MAXPATHLEN	PATH_MAX
// in https://opensource.apple.com/source/xnu/xnu-792.25.20/bsd/sys/syslimits.h
// #define	PATH_MAX		 1024
const MAXPATHLEN : usize = 1024;
const PROC_PIDPATHINFO_MAXSIZE : usize = 4 * MAXPATHLEN;

// this extern block links to the libproc library
#[link(name="proc", kind="dylib")]
extern {
    // Original signatures from http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c

    // int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)

    // int proc_pidinfo(int pid, int flavor, uint64_t arg,  void *buffer, int buffersize)

    // int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)

    // int proc_name(int pid, void * buffer, uint32_t buffersize)

    // int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)

    // int proc_kmsgbuf(void * buffer, uint32_t  buffersize)

    // int proc_pidpath(int pid, void * buffer, uint32_t  buffersize)
    fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize : uint32_t) -> c_int;

    // int proc_libversion(int *major, int * minor)
    // return value of 0 indicates success (inconsistent :-( )
    fn proc_libversion(major : *mut c_int, minor : * mut c_int) -> c_int;
}

fn get_errno_with_message(ret : i32) -> String {
    let e = errno();
    let code = e.0 as i32;
    format!("return code = {}, errno = {}, message = '{}'", ret, code, e)
}

pub fn pidpath(pid : i32) -> Result<String, String> {
    let pathbuf : Vec<u8>= Vec::with_capacity(PROC_PIDPATHINFO_MAXSIZE - 1);

    let buffer_ptr = pathbuf.as_ptr() as *mut c_void;
    let buffer_size = pathbuf.capacity() as u32;

    let ret : i32;
    let rebuilt : Vec<u8>;

    unsafe {
        ret = proc_pidpath(pid, buffer_ptr, buffer_size);
        rebuilt = Vec::from_raw_parts(buffer_ptr as *mut u8, ret as usize, buffer_size as usize);
    };

    if ret <= 0 {
        Err(get_errno_with_message(ret))
    } else {
        match String::from_utf8(rebuilt) {
            Ok(path) => Ok(path),
            Err(e) => Err(format!("Invalid UTF-8 sequence: {}", e))
        }
    }
}

#[test]
// This checks that it can find the path of the init process with PID 1
fn pidpath_test_init_pid() {
    match pidpath(1) {
        // run tests with 'cargo test -- --nocapture' to see the test output
        Ok(path) => println!("Path of init process PID = 1 is '{}'", path),
        Err(message) => assert!(true, message)
    }
}

#[test]
#[should_panic]
// This checks that it cannot find the path of the process with pid -1
fn pidpath_test_unknown_pid() {
    match pidpath(-1) {
        // run tests with 'cargo test -- --nocapture' to see the test output
        Ok(path) => assert!(false, "It found the path of process Pwith ID = -1 (path = {}), that's not possible\n", path),
        Err(message) => assert!(false, message)
    }
}

pub fn libversion() -> Result<(i32, i32), String> {
    let mut major = 0;
    let mut minor = 0;
    let ret : i32;

    unsafe {
        ret = proc_libversion(&mut major, &mut minor);
    };

    if ret == 0 {
        Ok((major, minor))
    } else {
        Err(get_errno_with_message(ret))
    }
}

#[test]
fn libversion_test() {
    match libversion() {
        Ok((major, minor)) => {
            // run tests with 'cargo test -- --nocapture' to see the test output
            println!("Major = {}, Minor = {}", major, minor);
        },
        Err(message) => assert!(false, message)
    }
}<commit_msg>Implemented proc_name() with a unit test<commit_after>extern crate libc;
use self::libc::{uint32_t, c_void, c_int};

extern crate errno;
use self::errno::errno;

use std::str;

// Since we cannot access C macros for constants from Rust - I have had to redefine this, based on Apple's source code
// See http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c
// buffersize must be more than PROC_PIDPATHINFO_SIZE
// buffersize must be less than PROC_PIDPATHINFO_MAXSIZE
//
// See http://opensource.apple.com//source/xnu/xnu-1456.1.26/bsd/sys/proc_info.h
// #define PROC_PIDPATHINFO_SIZE		(MAXPATHLEN)
// #define PROC_PIDPATHINFO_MAXSIZE	(4*MAXPATHLEN)
// in http://opensource.apple.com//source/xnu/xnu-1504.7.4/bsd/sys/param.h
// #define	MAXPATHLEN	PATH_MAX
// in https://opensource.apple.com/source/xnu/xnu-792.25.20/bsd/sys/syslimits.h
// #define	PATH_MAX		 1024
const MAXPATHLEN : usize = 1024;
const PROC_PIDPATHINFO_MAXSIZE : usize = 4 * MAXPATHLEN;

// this extern block links to the libproc library
#[link(name="proc", kind="dylib")]
extern {
    // Original signatures from http://opensource.apple.com/source/Libc/Libc-594.9.4/darwin/libproc.c

    // int proc_listpids(uint32_t type, uint32_t typeinfo, void *buffer, int buffersize)

    // int proc_pidinfo(int pid, int flavor, uint64_t arg,  void *buffer, int buffersize)

    // int proc_pidfdinfo(int pid, int fd, int flavor, void * buffer, int buffersize)

    fn proc_name(pid : c_int, buffer : *mut c_void, buffersize : uint32_t) -> c_int;

    // int proc_regionfilename(int pid, uint64_t address, void * buffer, uint32_t buffersize)

    // int proc_kmsgbuf(void * buffer, uint32_t  buffersize)

    // int proc_pidpath(int pid, void * buffer, uint32_t  buffersize)
    fn proc_pidpath(pid : c_int, buffer : *mut c_void, buffersize : uint32_t) -> c_int;

    // int proc_libversion(int *major, int * minor)
    // return value of 0 indicates success (inconsistent :-( )
    fn proc_libversion(major : *mut c_int, minor : * mut c_int) -> c_int;
}

fn get_errno_with_message(ret : i32) -> String {
    let e = errno();
    let code = e.0 as i32;
    format!("return code = {}, errno = {}, message = '{}'", ret, code, e)
}

pub fn pidpath(pid : i32) -> Result<String, String> {
    let pathbuf : Vec<u8>= Vec::with_capacity(PROC_PIDPATHINFO_MAXSIZE - 1);
    let buffer_ptr = pathbuf.as_ptr() as *mut c_void;
    let buffer_size = pathbuf.capacity() as u32;
    let ret : i32;
    let rebuilt : Vec<u8>;

    unsafe {
        ret = proc_pidpath(pid, buffer_ptr, buffer_size);
        rebuilt = Vec::from_raw_parts(buffer_ptr as *mut u8, ret as usize, buffer_size as usize);
    };

    if ret <= 0 {
        Err(get_errno_with_message(ret))
    } else {
        match String::from_utf8(rebuilt) {
            Ok(path) => Ok(path),
            Err(e) => Err(format!("Invalid UTF-8 sequence: {}", e))
        }
    }
}

#[test]
// This checks that it can find the path of the init process with PID 1
fn pidpath_test_init_pid() {
    match pidpath(1) {
        // run tests with 'cargo test -- --nocapture' to see the test output
        Ok(path) => println!("Path of init process PID = 1 is '{}'", path),
        Err(message) => assert!(true, message)
    }
}

#[test]
#[should_panic]
// This checks that it cannot find the path of the process with pid -1
fn pidpath_test_unknown_pid() {
    match pidpath(-1) {
        // run tests with 'cargo test -- --nocapture' to see the test output
        Ok(path) => assert!(false, "It found the path of process Pwith ID = -1 (path = {}), that's not possible\n", path),
        Err(message) => assert!(false, message)
    }
}

pub fn libversion() -> Result<(i32, i32), String> {
    let mut major = 0;
    let mut minor = 0;
    let ret : i32;

    unsafe {
        ret = proc_libversion(&mut major, &mut minor);
    };

    if ret == 0 {
        Ok((major, minor))
    } else {
        Err(get_errno_with_message(ret))
    }
}

#[test]
fn libversion_test() {
    match libversion() {
        Ok((major, minor)) => {
            // run tests with 'cargo test -- --nocapture' to see the test output
            println!("Major = {}, Minor = {}", major, minor);
        },
        Err(message) => assert!(false, message)
    }
}

pub fn name(pid : i32) -> Result<String, String> {
    let namebuf: Vec<u8>= Vec::with_capacity(PROC_PIDPATHINFO_MAXSIZE - 1);
    let buffer_ptr = namebuf.as_ptr() as *mut c_void;
    let buffer_size = namebuf.capacity() as u32;
    let ret : i32;
    let rebuilt : Vec<u8>;

    unsafe {
        ret = proc_name(pid, buffer_ptr, buffer_size);
        rebuilt = Vec::from_raw_parts(buffer_ptr as *mut u8, ret as usize, buffer_size as usize);
    };

    if ret <= 0 {
        Err(get_errno_with_message(ret))
    } else {
        match String::from_utf8(rebuilt) {
            Ok(name) => Ok(name),
            Err(e) => Err(format!("Invalid UTF-8 sequence: {}", e))
        }
    }
}

#[test]
// This checks that it can find the name of the init process with PID 1
fn name_test_init_pid() {
    match pidpath(1) {
        // run tests with 'cargo test -- --nocapture' to see the test output
        Ok(path) => println!("Name of init process PID = 1 is '{}'", path),
        Err(message) => assert!(true, message)
    }
}<|endoftext|>


<commit_before>// This examples allow to query all function exports of the
// provided wasm module

extern crate parity_wasm;

use std::env::args;

use parity_wasm::elements::{Internal, External, Type, FunctionType, Module};

// Auxillary function to resolve function type (signature) given it's callable index
fn type_by_index(module: &Module, index: usize) -> FunctionType {

    // Demand that function and type section exist. Otherwise, fail with a
    // corresponding error.
    let function_section = module.function_section().expect("No function section found");
    let type_section = module.type_section().expect("No type section found");

    // This counts the number of _function_ imports listed by the module, excluding
    // the globals, since indexing for actual functions for `call` and `export` purposes
    // includes both imported and own functions. So we actualy need the imported function count
    // to resolve actual index of the given function in own functions list.
    let import_section_len: usize = match module.import_section() {
            Some(import) =>
                import.entries().iter().filter(|entry| match entry.external() {
                    &External::Function(_) => true,
                    _ => false,
                    }).count(),
            None => 0,
        };

    // Substruct the value queried in the previous step from the provided index
    // to get own function index from which we can query type next.
    let function_index_in_section = index - import_section_len;

    // Query the own function given we have it's index
    let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;

    // Finally, return function type (signature)
    match type_section.types()[func_type_ref] {
        Type::Function(ref func_type) => func_type.clone(),
    }
}

fn main() {

    // Example executable takes one argument which must
    // refernce the existing file with a valid wasm module
    let args: Vec<_> = args().collect();
    if args.len() < 2 {
        println!("Prints export function names with and their types");
        println!("Usage: {} <wasm file>", args[0]);
        return;
    }

    // Here we load module using dedicated for this purpose
    // `deserialize_file` function (which works only with modules)
    let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");

    // Query the export section from the loaded module. Note that not every
    // wasm module obliged to contain export section. So in case there is no
    // any export section, we panic with the corresponding error.
    let export_section = module.export_section().expect("No export section found");

    // Process all exports, leaving only those which reference the internal function
    // of the wasm module
    let exports: Vec<String> = export_section.entries().iter()
        .filter_map(|entry|
            // This is match on export variant, which can either be function or global
            // We are intereseted only in functions for an example
            match *entry.internal() {
                // Return function export name (return by field() function and it's index)
                Internal::Function(index) => Some((entry.field(), index as usize)),
                _ => None
            })
        // Another map to resolve function signature index given it's internal index and return
        // the printable string of the export
        .map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();

    // Print the result
    for export in exports {
        println!("{:}", export);
    }
}
<commit_msg>fix spelling<commit_after>// This examples allow to query all function exports of the
// provided wasm module

extern crate parity_wasm;

use std::env::args;

use parity_wasm::elements::{Internal, External, Type, FunctionType, Module};

// Auxillary function to resolve function type (signature) given it's callable index
fn type_by_index(module: &Module, index: usize) -> FunctionType {

    // Demand that function and type section exist. Otherwise, fail with a
    // corresponding error.
    let function_section = module.function_section().expect("No function section found");
    let type_section = module.type_section().expect("No type section found");

    // This counts the number of _function_ imports listed by the module, excluding
    // the globals, since indexing for actual functions for `call` and `export` purposes
    // includes both imported and own functions. So we actualy need the imported function count
    // to resolve actual index of the given function in own functions list.
    let import_section_len: usize = match module.import_section() {
            Some(import) =>
                import.entries().iter().filter(|entry| match entry.external() {
                    &External::Function(_) => true,
                    _ => false,
                    }).count(),
            None => 0,
        };

    // Substract the value queried in the previous step from the provided index
    // to get own function index from which we can query type next.
    let function_index_in_section = index - import_section_len;

    // Query the own function given we have it's index
    let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;

    // Finally, return function type (signature)
    match type_section.types()[func_type_ref] {
        Type::Function(ref func_type) => func_type.clone(),
    }
}

fn main() {

    // Example executable takes one argument which must
    // refernce the existing file with a valid wasm module
    let args: Vec<_> = args().collect();
    if args.len() < 2 {
        println!("Prints export function names with and their types");
        println!("Usage: {} <wasm file>", args[0]);
        return;
    }

    // Here we load module using dedicated for this purpose
    // `deserialize_file` function (which works only with modules)
    let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");

    // Query the export section from the loaded module. Note that not every
    // wasm module obliged to contain export section. So in case there is no
    // any export section, we panic with the corresponding error.
    let export_section = module.export_section().expect("No export section found");

    // Process all exports, leaving only those which reference the internal function
    // of the wasm module
    let exports: Vec<String> = export_section.entries().iter()
        .filter_map(|entry|
            // This is match on export variant, which can either be function or global
            // We are intereseted only in functions for an example
            match *entry.internal() {
                // Return function export name (return by field() function and it's index)
                Internal::Function(index) => Some((entry.field(), index as usize)),
                _ => None
            })
        // Another map to resolve function signature index given it's internal index and return
        // the printable string of the export
        .map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();

    // Print the result
    for export in exports {
        println!("{:}", export);
    }
}
<|endoftext|>


<commit_before>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: i32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new().unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read() {
            println!("{:?}", event);
        }
    }
}
<commit_msg>Pass buffer size<commit_after>extern crate portmidi as pm;

extern crate rustc_serialize;
extern crate docopt;

const USAGE: &'static str = r#"
portmidi-rs: monitor-device example

Usage:
    monitor-device <id>

Options:
    -h --help   Show this screen.

Omitting <id> will list the available devices.
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_id: i32,
}

fn print_devices(pm: &pm::PortMidi) {
    for dev in pm.devices().unwrap() {
        println!("{}", dev);
    }
}

fn main() {
    let context = pm::PortMidi::new(1024).unwrap();
    let args: Args = docopt::Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|err| {
        print_devices(&context);
        err.exit();
    });
    let info = context.device(args.arg_id).unwrap();
    println!("Listening on: {}) {}", info.id(), info.name());

    let mut in_port = context.input_port(info).unwrap();
    while let Ok(_) = in_port.poll() {
        if let Ok(Some(event)) = in_port.read() {
            println!("{:?}", event);
        }
    }
}
<|endoftext|>


<commit_before>use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::net::SocketAddr;
use std::time::SystemTime;

use messages::utils::{U64, SystemTimeSerdeHelper};
use crypto::{Hash, PublicKey, Signature};
use blockchain;
use super::{RawMessage, BitVec};

pub const CONSENSUS: u16 = 0;

pub const CONNECT_MESSAGE_ID: u16 = 0;
pub const STATUS_MESSAGE_ID: u16 = 1;

pub const PROPOSE_MESSAGE_ID: u16 = 2;
pub const PREVOTE_MESSAGE_ID: u16 = 3;
pub const PRECOMMIT_MESSAGE_ID: u16 = 4;
pub const BLOCK_MESSAGE_ID: u16 = 5;

pub const REQUEST_PROPOSE_MESSAGE_ID: u16 = 6;
pub const REQUEST_TRANSACTIONS_MESSAGE_ID: u16 = 7;
pub const REQUEST_PREVOTES_MESSAGE_ID: u16 = 8;
pub const REQUEST_PEERS_MESSAGE_ID: u16 = 9;
pub const REQUEST_BLOCK_MESSAGE_ID: u16 = 10;

// Node connection
message! {
    Connect {
        const TYPE = CONSENSUS;
        const ID = CONNECT_MESSAGE_ID;
        const SIZE = 50;

        pub_key:        &PublicKey  [00 => 32]
        addr:           SocketAddr  [32 => 38]
        time:           SystemTime  [38 => 50]
    }
}

// Consensus
message! {
    Propose {
        const TYPE = CONSENSUS;
        const ID = PROPOSE_MESSAGE_ID;
        const SIZE = 56;

        validator:      u32         [00 => 04]
        height:         u64         [04 => 12]
        round:          u32         [12 => 16]
        prev_hash:      &Hash       [16 => 48]
        transactions:   &[Hash]     [48 => 56]
    }
}

// Consensus
message! {
    Prevote {
        const TYPE = CONSENSUS;
        const ID = PREVOTE_MESSAGE_ID;
        const SIZE = 52;

        validator:      u32         [00 => 04]
        height:         u64         [04 => 12]
        round:          u32         [12 => 16]
        propose_hash:   &Hash       [16 => 48]
        locked_round:   u32         [48 => 52]
    }
}

// Consensus
message! {
    Precommit {
        const TYPE = CONSENSUS;
        const ID = PRECOMMIT_MESSAGE_ID;
        const SIZE = 96;

        validator:      u32         [00 => 04]
        height:         u64         [08 => 16]
        round:          u32         [16 => 20]
        propose_hash:   &Hash       [20 => 52]
        block_hash:     &Hash       [52 => 84]
        time:           SystemTime  [84 => 96]
    }
}

#[derive(Serialize, Deserialize)]
struct PrecommitSerdeHelper {
    body: PrecommitBodySerdeHelper,
    signature: Signature,
}

#[derive(Serialize, Deserialize)]
struct PrecommitBodySerdeHelper {
   validator: u32,
   height: U64,
   round: u32,
   propose_hash: Hash,
   block_hash: Hash,
   time: SystemTimeSerdeHelper,
}

impl Serialize for Precommit {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        let body = PrecommitBodySerdeHelper{
            validator: self.validator(),
            height: U64(self.height()),
            round: self.round(),
            propose_hash: *self.propose_hash(),
            block_hash: *self.block_hash(),
            time: SystemTimeSerdeHelper(self.time()),
        };
        let helper = PrecommitSerdeHelper {
            body: body,
            signature: *self.raw.signature(),
        };
        helper.serialize(ser)
    }
}

impl Deserialize for Precommit {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        let h = <PrecommitSerdeHelper>::deserialize(deserializer)?;

        let precommit = Precommit::new_with_signature(h.body.validator, h.body.height.0, h.body.round, &h.body.propose_hash, &h.body.block_hash, h.body.time.0, &h.signature);
        Ok(precommit)
    }
}

// Message with current state.
message! {
    Status {
        const TYPE = CONSENSUS;
        const ID = STATUS_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey          [00 => 32]
        height:         u64                 [32 => 40]
        last_hash:      &Hash               [40 => 72]
    }
}

// Response to `RequestBlock`.
message! {
    Block {
        const TYPE = CONSENSUS;
        const ID = BLOCK_MESSAGE_ID;
        const SIZE = 88;

        from:           &PublicKey          [00 => 32]
        to:             &PublicKey          [32 => 64]
        block:          blockchain::Block   [64 => 72]
        precommits:     Vec<Precommit>      [72 => 80]
        transactions:   Vec<RawMessage>     [80 => 88]
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BlockProof {
    pub block: blockchain::Block,
    pub precommits: Vec<Precommit>,
}

// `Propose` request.
message! {
    RequestPropose {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PROPOSE_MESSAGE_ID;
        const SIZE = 104;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
        propose_hash:   &Hash       [72 => 104]
    }
}

// Request for transactions by hash.
message! {
    RequestTransactions {
        const TYPE = CONSENSUS;
        const ID = REQUEST_TRANSACTIONS_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        txs:            &[Hash]     [64 => 72]
    }
}

// Prevotes request.
message! {
    RequestPrevotes {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PREVOTES_MESSAGE_ID;
        const SIZE = 116;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
        round:          u32         [72 => 76]
        propose_hash:   &Hash       [76 => 108]
        validators:     BitVec      [108 => 116]
    }
}

// Peers request.
message! {
    RequestPeers {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PEERS_MESSAGE_ID;
        const SIZE = 64;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
    }
}

// `Block` request.
message! {
    RequestBlock {
        const TYPE = CONSENSUS;
        const ID = REQUEST_BLOCK_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
    }
}
<commit_msg>Add documentation template<commit_after>use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::net::SocketAddr;
use std::time::SystemTime;

use messages::utils::{U64, SystemTimeSerdeHelper};
use crypto::{Hash, PublicKey, Signature};
use blockchain;
use super::{RawMessage, BitVec};

pub const CONSENSUS: u16 = 0;

pub const CONNECT_MESSAGE_ID: u16 = 0;
pub const STATUS_MESSAGE_ID: u16 = 1;

pub const PROPOSE_MESSAGE_ID: u16 = 2;
pub const PREVOTE_MESSAGE_ID: u16 = 3;
pub const PRECOMMIT_MESSAGE_ID: u16 = 4;
pub const BLOCK_MESSAGE_ID: u16 = 5;

pub const REQUEST_PROPOSE_MESSAGE_ID: u16 = 6;
pub const REQUEST_TRANSACTIONS_MESSAGE_ID: u16 = 7;
pub const REQUEST_PREVOTES_MESSAGE_ID: u16 = 8;
pub const REQUEST_PEERS_MESSAGE_ID: u16 = 9;
pub const REQUEST_BLOCK_MESSAGE_ID: u16 = 10;

// Node connection
message! {
    Connect {
        const TYPE = CONSENSUS;
        const ID = CONNECT_MESSAGE_ID;
        const SIZE = 50;

        pub_key:        &PublicKey  [00 => 32]
        addr:           SocketAddr  [32 => 38]
        time:           SystemTime  [38 => 50]
    }
}

// Consensus
message! {
    Propose {
        const TYPE = CONSENSUS;
        const ID = PROPOSE_MESSAGE_ID;
        const SIZE = 56;

        validator:      u32         [00 => 04]
        height:         u64         [04 => 12]
        round:          u32         [12 => 16]
        prev_hash:      &Hash       [16 => 48]
        transactions:   &[Hash]     [48 => 56]
    }
}

// Consensus
message! {
    Prevote {
        const TYPE = CONSENSUS;
        const ID = PREVOTE_MESSAGE_ID;
        const SIZE = 52;

        validator:      u32         [00 => 04]
        height:         u64         [04 => 12]
        round:          u32         [12 => 16]
        propose_hash:   &Hash       [16 => 48]
        locked_round:   u32         [48 => 52]
    }
}

// Consensus
message! {
    Precommit {
        const TYPE = CONSENSUS;
        const ID = PRECOMMIT_MESSAGE_ID;
        const SIZE = 96;

        validator:      u32         [00 => 04]
        height:         u64         [08 => 16]
        round:          u32         [16 => 20]
        propose_hash:   &Hash       [20 => 52]
        block_hash:     &Hash       [52 => 84]
        time:           SystemTime  [84 => 96]
    }
}

#[derive(Serialize, Deserialize)]
struct PrecommitSerdeHelper {
    body: PrecommitBodySerdeHelper,
    signature: Signature,
}

#[derive(Serialize, Deserialize)]
struct PrecommitBodySerdeHelper {
   validator: u32,
   height: U64,
   round: u32,
   propose_hash: Hash,
   block_hash: Hash,
   time: SystemTimeSerdeHelper,
}

impl Serialize for Precommit {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        let body = PrecommitBodySerdeHelper{
            validator: self.validator(),
            height: U64(self.height()),
            round: self.round(),
            propose_hash: *self.propose_hash(),
            block_hash: *self.block_hash(),
            time: SystemTimeSerdeHelper(self.time()),
        };
        let helper = PrecommitSerdeHelper {
            body: body,
            signature: *self.raw.signature(),
        };
        helper.serialize(ser)
    }
}

impl Deserialize for Precommit {
    fn deserialize<D>(deserializer: &mut D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        let h = <PrecommitSerdeHelper>::deserialize(deserializer)?;

        let precommit = Precommit::new_with_signature(h.body.validator, h.body.height.0, h.body.round, &h.body.propose_hash, &h.body.block_hash, h.body.time.0, &h.signature);
        Ok(precommit)
    }
}

// Message with current state.
message! {
    Status {
        const TYPE = CONSENSUS;
        const ID = STATUS_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey          [00 => 32]
        height:         u64                 [32 => 40]
        last_hash:      &Hash               [40 => 72]
    }
}

// Response to `RequestBlock`.
message! {
    Block {
        const TYPE = CONSENSUS;
        const ID = BLOCK_MESSAGE_ID;
        const SIZE = 88;

        from:           &PublicKey          [00 => 32]
        to:             &PublicKey          [32 => 64]
        block:          blockchain::Block   [64 => 72]
        precommits:     Vec<Precommit>      [72 => 80]
        transactions:   Vec<RawMessage>     [80 => 88]
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BlockProof {
    pub block: blockchain::Block,
    pub precommits: Vec<Precommit>,
}

// `Propose` request.
message! {
    RequestPropose {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PROPOSE_MESSAGE_ID;
        const SIZE = 104;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
        propose_hash:   &Hash       [72 => 104]
    }
}

// Request for transactions by hash.
message! {
    RequestTransactions {
        const TYPE = CONSENSUS;
        const ID = REQUEST_TRANSACTIONS_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        txs:            &[Hash]     [64 => 72]
    }
}

// Prevotes request.
message! {
    RequestPrevotes {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PREVOTES_MESSAGE_ID;
        const SIZE = 116;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
        round:          u32         [72 => 76]
        propose_hash:   &Hash       [76 => 108]
        validators:     BitVec      [108 => 116]
    }
}

/// Request connected peers from the node `to`.
///
/// ### Processing
///   * The message is authenticated by the pubkey `from`.
///     It must be in the receiver's full node list
///   * If the message is properly authorized, the node responds with...
///
/// ### Generation
/// A node generates `RequestPeers` under such and such conditions...
message! {
    RequestPeers {
        const TYPE = CONSENSUS;
        const ID = REQUEST_PEERS_MESSAGE_ID;
        const SIZE = 64;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
    }
}

// `Block` request.
message! {
    RequestBlock {
        const TYPE = CONSENSUS;
        const ID = REQUEST_BLOCK_MESSAGE_ID;
        const SIZE = 72;

        from:           &PublicKey  [00 => 32]
        to:             &PublicKey  [32 => 64]
        height:         u64         [64 => 72]
    }
}
<|endoftext|>


<commit_before>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod function_manifest;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod patch;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;

use crate::load::read_bytes;
pub use crate::{
    compiler::Compiler,
    compiler::OptLevel,
    error::{LucetcError, LucetcErrorKind},
    heap::HeapSettings,
    load::read_module,
    patch::patch_module,
};
use failure::{format_err, Error, ResultExt};
use lucet_module_data::bindings::Bindings;
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use tempfile;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    opt_level: OptLevel,
    heap: HeapSettings,
    builtins_paths: Vec<PathBuf>,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn builtins<P: AsRef<Path>>(&mut self, builtins_path: P);
    fn with_builtins<P: AsRef<Path>>(self, builtins_path: P) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().opt_level = opt_level;
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn builtins<P: AsRef<Path>>(&mut self, builtins_path: P) {
        self.as_lucetc()
            .builtins_paths
            .push(builtins_path.as_ref().to_owned());
    }

    fn with_builtins<P: AsRef<Path>>(mut self, builtins_path: P) -> Self {
        self.builtins(builtins_path);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc().heap.min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc().heap.max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc().heap.min_reserved_size = reserved_size;
        self.as_lucetc().heap.max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().heap.guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_paths: vec![],
            pk: None,
            sk: None,
            sign: false,
            verify: false,
        }
    }

    pub fn try_from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_paths: vec![],
            pk: None,
            sk: None,
            sign: false,
            verify: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        use parity_wasm::elements::{deserialize_buffer, serialize};

        let mut builtins_bindings = vec![];
        let mut module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => read_module(&path, &self.pk, self.verify)?,
        };

        if !self.builtins_paths.is_empty() {
            let mut module = deserialize_buffer(&module_binary)?;
            for builtins in self.builtins_paths.iter() {
                let (newmodule, builtins_map) = patch_module(module, builtins)?;
                module = newmodule;
                builtins_bindings.push(Bindings::env(builtins_map));
            }
            module_binary = serialize(module)?;
        }

        let mut bindings = Bindings::empty();

        for binding in builtins_bindings.iter().chain(self.bindings.iter()) {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = Compiler::new(
            &module_contents,
            self.opt_level,
            &bindings,
            self.heap.clone(),
        )?;
        let obj = compiler.object_file()?;

        obj.write(output.as_ref()).context("writing object file")?;
        Ok(())
    }

    pub fn clif_ir<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = Compiler::new(
            &module_contents,
            self.opt_level,
            &bindings,
            self.heap.clone(),
        )?;

        compiler
            .cranelift_funcs()?
            .write(&output)
            .context("writing clif file")?;

        Ok(())
    }

    pub fn shared_object_file<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, &output)?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(
                format_err!("signing requires a secret key").context(LucetcErrorKind::Signature),
            )?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

#[cfg(not(target_os = "macos"))]
const LDFLAGS_DEFAULT: &str = "-shared";

#[cfg(target_os = "macos")]
const LDFLAGS_DEFAULT: &str = "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup";

fn link_so<P, Q>(objpath: P, sopath: Q) -> Result<(), Error>
where
    P: AsRef<Path>,
    Q: AsRef<Path>,
{
    use std::process::Command;
    let mut cmd_ld = Command::new(env::var("LD").unwrap_or(LD_DEFAULT.into()));
    cmd_ld.arg(objpath.as_ref());
    let env_ldflags = env::var("LDFLAGS").unwrap_or(LDFLAGS_DEFAULT.into());
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }
    cmd_ld.arg("-o");
    cmd_ld.arg(sopath.as_ref());

    let run_ld = cmd_ld
        .output()
        .context(format_err!("running ld on {:?}", objpath.as_ref()))?;

    if !run_ld.status.success() {
        Err(format_err!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        ))?;
    }
    Ok(())
}
<commit_msg>lucetc: pub use Bindings<commit_after>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod function_manifest;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod patch;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;

use crate::load::read_bytes;
pub use crate::{
    compiler::Compiler,
    compiler::OptLevel,
    error::{LucetcError, LucetcErrorKind},
    heap::HeapSettings,
    load::read_module,
    patch::patch_module,
};
use failure::{format_err, Error, ResultExt};
pub use lucet_module_data::bindings::Bindings;
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use tempfile;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    opt_level: OptLevel,
    heap: HeapSettings,
    builtins_paths: Vec<PathBuf>,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn builtins<P: AsRef<Path>>(&mut self, builtins_path: P);
    fn with_builtins<P: AsRef<Path>>(self, builtins_path: P) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().opt_level = opt_level;
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn builtins<P: AsRef<Path>>(&mut self, builtins_path: P) {
        self.as_lucetc()
            .builtins_paths
            .push(builtins_path.as_ref().to_owned());
    }

    fn with_builtins<P: AsRef<Path>>(mut self, builtins_path: P) -> Self {
        self.builtins(builtins_path);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc().heap.min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc().heap.max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc().heap.min_reserved_size = reserved_size;
        self.as_lucetc().heap.max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().heap.guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_paths: vec![],
            pk: None,
            sk: None,
            sign: false,
            verify: false,
        }
    }

    pub fn try_from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            opt_level: OptLevel::default(),
            heap: HeapSettings::default(),
            builtins_paths: vec![],
            pk: None,
            sk: None,
            sign: false,
            verify: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        use parity_wasm::elements::{deserialize_buffer, serialize};

        let mut builtins_bindings = vec![];
        let mut module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => read_module(&path, &self.pk, self.verify)?,
        };

        if !self.builtins_paths.is_empty() {
            let mut module = deserialize_buffer(&module_binary)?;
            for builtins in self.builtins_paths.iter() {
                let (newmodule, builtins_map) = patch_module(module, builtins)?;
                module = newmodule;
                builtins_bindings.push(Bindings::env(builtins_map));
            }
            module_binary = serialize(module)?;
        }

        let mut bindings = Bindings::empty();

        for binding in builtins_bindings.iter().chain(self.bindings.iter()) {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = Compiler::new(
            &module_contents,
            self.opt_level,
            &bindings,
            self.heap.clone(),
        )?;
        let obj = compiler.object_file()?;

        obj.write(output.as_ref()).context("writing object file")?;
        Ok(())
    }

    pub fn clif_ir<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = Compiler::new(
            &module_contents,
            self.opt_level,
            &bindings,
            self.heap.clone(),
        )?;

        compiler
            .cranelift_funcs()?
            .write(&output)
            .context("writing clif file")?;

        Ok(())
    }

    pub fn shared_object_file<P: AsRef<Path>>(&self, output: P) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, &output)?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(
                format_err!("signing requires a secret key").context(LucetcErrorKind::Signature),
            )?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

#[cfg(not(target_os = "macos"))]
const LDFLAGS_DEFAULT: &str = "-shared";

#[cfg(target_os = "macos")]
const LDFLAGS_DEFAULT: &str = "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup";

fn link_so<P, Q>(objpath: P, sopath: Q) -> Result<(), Error>
where
    P: AsRef<Path>,
    Q: AsRef<Path>,
{
    use std::process::Command;
    let mut cmd_ld = Command::new(env::var("LD").unwrap_or(LD_DEFAULT.into()));
    cmd_ld.arg(objpath.as_ref());
    let env_ldflags = env::var("LDFLAGS").unwrap_or(LDFLAGS_DEFAULT.into());
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }
    cmd_ld.arg("-o");
    cmd_ld.arg(sopath.as_ref());

    let run_ld = cmd_ld
        .output()
        .context(format_err!("running ld on {:?}", objpath.as_ref()))?;

    if !run_ld.status.success() {
        Err(format_err!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        ))?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate postgres;

use std::fs::File;
use std::io::{Write, BufWriter};
use std::collections::HashMap;

use self::postgres::Connection;

type CvName = String;

pub type MiscExtRange = String;

pub type GeneUniquename = String;
pub type TermUniquename = String;
pub type GeneName = String;
pub type TypeName = String;
pub type GeneProduct = String;

pub type TermName = String;
pub type TermId = String;
pub type TermDef = String;

pub type Evidence = String;
pub type With = String;
pub type Residue = String;
pub type Condition = String;
pub type Qualifier = String;

pub type TypeInteractionAnnotationMap =
    HashMap<TypeName, Vec<InteractionAnnotation>>;

pub type UniquenameGeneMap =
    HashMap<GeneUniquename, GeneDetails>;

pub type TranscriptUniquename = String;

pub type UniquenameTranscriptMap =
    HashMap<TranscriptUniquename, TranscriptDetails>;

pub type GenotypeUniquename = String;
pub type AlleleUniquename = String;

pub type UniquenameAlleleMap = HashMap<AlleleUniquename, AlleleShort>;
pub type UniquenameGenotypeMap = HashMap<GenotypeUniquename, GenotypeShort>;

pub type IdGeneMap = HashMap<GeneUniquename, GeneDetails>;
pub type IdGeneShortMap = HashMap<GeneUniquename, GeneShort>;
pub type IdTermShortMap = HashMap<TermId, Rc<TermShort>>;
pub type IdTermDetailsMap = HashMap<TermId, Rc<TermDetails>>;
pub type IdReferenceMap = HashMap<TermId, ReferenceDetails>;

include!(concat!(env!("OUT_DIR"), "/data_serde.rs"));

impl WebData {
    fn get_genes(&self) -> &IdGeneMap {
        &self.genes
    }
    fn get_terms(&self) -> &IdTermDetailsMap {
        &self.terms
    }

    fn write_reference_details(&self, output_dir: &str) {
        for (reference_uniquename, reference_details) in &self.references {
            let s = serde_json::to_string(&reference_details).unwrap();
            let file_name = String::new() + &output_dir + "/reference/" + &reference_uniquename + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write!");
        }
    }

    fn write_gene_details(&self, output_dir: &str) {
        for (gene_uniquename, gene_details) in &self.genes {
            let s = serde_json::to_string(&gene_details).unwrap();
            let file_name = String::new() + &output_dir + "/gene/" + &gene_uniquename + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write!");
        }
    }

    fn write_gene_summary(&self, output_dir: &str, organism_genus_species: &str) {
        let filtered_gene_summaries =
            self.search_api_maps.gene_summaries.iter()
            .filter(|gene_short| {
                let gene_uniquename = &gene_short.uniquename;
                let gene_details = self.get_genes().get(gene_uniquename).unwrap();
                let feature_org_genus_species = String::new() +
                    &gene_details.organism.genus + "_" + &gene_details.organism.species;
                feature_org_genus_species == organism_genus_species
            })
            .map(|gene_short| gene_short.clone())
            .collect::<Vec<GeneShort>>();
        let s = serde_json::to_string(&filtered_gene_summaries).unwrap();
        let file_name = String::new() + &output_dir + "/gene_summaries.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

    fn write_terms(&self, output_dir: &str) {
        for (termid, term_details) in &self.terms {
            let s = serde_json::to_string(&term_details).unwrap();
            let file_name = String::new() + &output_dir + "/term/" + &termid + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write!");
        }
    }

    fn write_metadata(&self, output_dir: &str) {
        let s = serde_json::to_string(&self.metadata).unwrap();
        let file_name = String::new() + &output_dir + "/metadata.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

    fn write_search_api_maps(&self, output_dir: &str) {
        let s = serde_json::to_string(&self.search_api_maps).unwrap();
        let file_name = String::new() + &output_dir + "/search_api_maps.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

    pub fn write(&self, output_dir: &str, organism_genus_species: &str) {
        self.write_reference_details(output_dir);
        self.write_gene_details(output_dir);
        self.write_gene_summary(output_dir, organism_genus_species);
        self.write_terms(output_dir);
        self.write_metadata(output_dir);
        self.write_search_api_maps(output_dir);

        println!("wrote {} genes", self.get_genes().len());
        println!("wrote {} terms", self.get_terms().len());
    }

    pub fn store_jsonb(&self, conn: &Connection) {
        let trans = conn.transaction().unwrap();

        for (uniquename, gene_details) in &self.genes {
            let serde_value = serde_json::value::to_value(&gene_details);
            trans.execute("INSERT INTO web_json.gene (uniquename, data) values ($1, $2)",
                          &[&uniquename, &serde_value]).unwrap();
        }
        for (uniquename, ref_details) in &self.references {
            let serde_value = serde_json::value::to_value(&ref_details);
            trans.execute("INSERT INTO web_json.reference (uniquename, data) values ($1, $2)",
                          &[&uniquename, &serde_value]).unwrap();
        }
        for (termid, term_details) in &self.terms {
            let serde_value = serde_json::value::to_value(&term_details);
            trans.execute("INSERT INTO web_json.term (termid, data) values ($1, $2)",
                         &[&termid, &serde_value]).unwrap();
        }

        trans.execute("CREATE INDEX gene_jsonb_idx ON web_json.gene USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX gene_jsonb_name_idx ON web_json.gene USING gin ((data->>'name') gin_trgm_ops);", &[]).unwrap();
        trans.execute("CREATE INDEX term_jsonb_idx ON web_json.term USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX term_jsonb_name_idx ON web_json.term USING gin ((data->>'name') gin_trgm_ops);", &[]).unwrap();
        trans.execute("CREATE INDEX reference_jsonb_idx ON web_json.reference USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX reference_jsonb_title_idx ON web_json.reference USING gin ((data->>'title') gin_trgm_ops);", &[]).unwrap();

        trans.commit().unwrap();
    }
}
<commit_msg>Use less excited messages if writing fails<commit_after>extern crate serde_json;
extern crate postgres;

use std::fs::File;
use std::io::{Write, BufWriter};
use std::collections::HashMap;

use self::postgres::Connection;

type CvName = String;

pub type MiscExtRange = String;

pub type GeneUniquename = String;
pub type TermUniquename = String;
pub type GeneName = String;
pub type TypeName = String;
pub type GeneProduct = String;

pub type TermName = String;
pub type TermId = String;
pub type TermDef = String;

pub type Evidence = String;
pub type With = String;
pub type Residue = String;
pub type Condition = String;
pub type Qualifier = String;

pub type TypeInteractionAnnotationMap =
    HashMap<TypeName, Vec<InteractionAnnotation>>;

pub type UniquenameGeneMap =
    HashMap<GeneUniquename, GeneDetails>;

pub type TranscriptUniquename = String;

pub type UniquenameTranscriptMap =
    HashMap<TranscriptUniquename, TranscriptDetails>;

pub type GenotypeUniquename = String;
pub type AlleleUniquename = String;

pub type UniquenameAlleleMap = HashMap<AlleleUniquename, AlleleShort>;
pub type UniquenameGenotypeMap = HashMap<GenotypeUniquename, GenotypeShort>;

pub type IdGeneMap = HashMap<GeneUniquename, GeneDetails>;
pub type IdGeneShortMap = HashMap<GeneUniquename, GeneShort>;
pub type IdTermShortMap = HashMap<TermId, Rc<TermShort>>;
pub type IdTermDetailsMap = HashMap<TermId, Rc<TermDetails>>;
pub type IdReferenceMap = HashMap<TermId, ReferenceDetails>;

include!(concat!(env!("OUT_DIR"), "/data_serde.rs"));

impl WebData {
    fn get_genes(&self) -> &IdGeneMap {
        &self.genes
    }
    fn get_terms(&self) -> &IdTermDetailsMap {
        &self.terms
    }

    fn write_reference_details(&self, output_dir: &str) {
        for (reference_uniquename, reference_details) in &self.references {
            let s = serde_json::to_string(&reference_details).unwrap();
            let file_name = String::new() + &output_dir + "/reference/" + &reference_uniquename + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write reference JSON");
        }
    }

    fn write_gene_details(&self, output_dir: &str) {
        for (gene_uniquename, gene_details) in &self.genes {
            let s = serde_json::to_string(&gene_details).unwrap();
            let file_name = String::new() + &output_dir + "/gene/" + &gene_uniquename + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write gene JSON");
        }
    }

    fn write_gene_summary(&self, output_dir: &str, organism_genus_species: &str) {
        let filtered_gene_summaries =
            self.search_api_maps.gene_summaries.iter()
            .filter(|gene_short| {
                let gene_uniquename = &gene_short.uniquename;
                let gene_details = self.get_genes().get(gene_uniquename).unwrap();
                let feature_org_genus_species = String::new() +
                    &gene_details.organism.genus + "_" + &gene_details.organism.species;
                feature_org_genus_species == organism_genus_species
            })
            .map(|gene_short| gene_short.clone())
            .collect::<Vec<GeneShort>>();
        let s = serde_json::to_string(&filtered_gene_summaries).unwrap();
        let file_name = String::new() + &output_dir + "/gene_summaries.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write gene_summaries.json");
    }

    fn write_terms(&self, output_dir: &str) {
        for (termid, term_details) in &self.terms {
            let s = serde_json::to_string(&term_details).unwrap();
            let file_name = String::new() + &output_dir + "/term/" + &termid + ".json";
            let f = File::create(file_name).expect("Unable to open file");
            let mut writer = BufWriter::new(&f);
            writer.write_all(s.as_bytes()).expect("Unable to write term JSON");
        }
    }

    fn write_metadata(&self, output_dir: &str) {
        let s = serde_json::to_string(&self.metadata).unwrap();
        let file_name = String::new() + &output_dir + "/metadata.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write metadata.json");
    }

    fn write_search_api_maps(&self, output_dir: &str) {
        let s = serde_json::to_string(&self.search_api_maps).unwrap();
        let file_name = String::new() + &output_dir + "/search_api_maps.json";
        let f = File::create(file_name).expect("Unable to open file");
        let mut writer = BufWriter::new(&f);
        writer.write_all(s.as_bytes()).expect("Unable to write!");
    }

    pub fn write(&self, output_dir: &str, organism_genus_species: &str) {
        self.write_reference_details(output_dir);
        self.write_gene_details(output_dir);
        self.write_gene_summary(output_dir, organism_genus_species);
        self.write_terms(output_dir);
        self.write_metadata(output_dir);
        self.write_search_api_maps(output_dir);

        println!("wrote {} genes", self.get_genes().len());
        println!("wrote {} terms", self.get_terms().len());
    }

    pub fn store_jsonb(&self, conn: &Connection) {
        let trans = conn.transaction().unwrap();

        for (uniquename, gene_details) in &self.genes {
            let serde_value = serde_json::value::to_value(&gene_details);
            trans.execute("INSERT INTO web_json.gene (uniquename, data) values ($1, $2)",
                          &[&uniquename, &serde_value]).unwrap();
        }
        for (uniquename, ref_details) in &self.references {
            let serde_value = serde_json::value::to_value(&ref_details);
            trans.execute("INSERT INTO web_json.reference (uniquename, data) values ($1, $2)",
                          &[&uniquename, &serde_value]).unwrap();
        }
        for (termid, term_details) in &self.terms {
            let serde_value = serde_json::value::to_value(&term_details);
            trans.execute("INSERT INTO web_json.term (termid, data) values ($1, $2)",
                         &[&termid, &serde_value]).unwrap();
        }

        trans.execute("CREATE INDEX gene_jsonb_idx ON web_json.gene USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX gene_jsonb_name_idx ON web_json.gene USING gin ((data->>'name') gin_trgm_ops);", &[]).unwrap();
        trans.execute("CREATE INDEX term_jsonb_idx ON web_json.term USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX term_jsonb_name_idx ON web_json.term USING gin ((data->>'name') gin_trgm_ops);", &[]).unwrap();
        trans.execute("CREATE INDEX reference_jsonb_idx ON web_json.reference USING gin (data jsonb_path_ops)", &[]).unwrap();
        trans.execute("CREATE INDEX reference_jsonb_title_idx ON web_json.reference USING gin ((data->>'title') gin_trgm_ops);", &[]).unwrap();

        trans.commit().unwrap();
    }
}
<|endoftext|>