<commit_before>#[doc(hidden)]
#[macro_export]
macro_rules! primitive_cast {
    (0, $name:expr) => {
        $name as fn() -> _
    };
    (1, $name:expr) => {
        $name as fn(_) -> _
    };
    (2, $name:expr) => {
        $name as fn(_, _) -> _
    };
    (3, $name:expr) => {
        $name as fn(_, _, _) -> _
    };
    (4, $name:expr) => {
        $name as fn(_, _, _, _) -> _
    };
    (5, $name:expr) => {
        $name as fn(_, _, _, _, _) -> _
    };
    (6, $name:expr) => {
        $name as fn(_, _, _, _, _, _) -> _
    };
    (7, $name:expr) => {
        $name as fn(_, _, _, _, _, _, _) -> _
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! closure_wrapper {
    (0, $name:expr) => {
        || $crate::api::FutureResult::new($name())
    };
    (1, $name:expr) => {
        |a| $crate::api::FutureResult::new($name(a))
    };
    (2, $name:expr) => {
        |a, b| $crate::api::FutureResult::new($name(a, b))
    };
    (3, $name:expr) => {
        |a, b, c| $crate::api::FutureResult::new($name(a, b, c))
    };
    (4, $name:expr) => {
        |a, b, c, d| $crate::api::FutureResult::new($name(a, b, c, d))
    };
    (5, $name:expr) => {
        |a, b, c, d, e| $crate::api::FutureResult::new($name(a, b, c, d, e))
    };
    (6, $name:expr) => {
        |a, b, c, d, e, f| $crate::api::FutureResult::new($name(a, b, c, d, e, f))
    };
    (7, $name:expr) => {
        |a, b, c, d, e, f, g| $crate::api::FutureResult::new($name(a, b, c, d, e, f, g))
    };
}

/// Creates a `GluonFunction` from a function implementing `VMFunction`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn test(_x: i32, _y: String) -> f64 {
///     panic!()
/// }
///
/// fn main() {
///     primitive!(2, test);
/// }
/// ```
#[macro_export]
macro_rules! primitive {
    ($arg_count:tt, async fn $name:expr) => {
        primitive!($arg_count, stringify!($name), async fn $name)
    };

    ($arg_count:tt, $name:expr) => {
        primitive!($arg_count, stringify!($name), $name)
    };
    ($arg_count:tt, $name:expr, async fn $func:expr) => {
        primitive!($arg_count, $name, closure_wrapper!($arg_count, $func))
    };
    ($arg_count:tt, $name:expr, $func:expr) => {
        unsafe {
            extern "C" fn wrapper(thread: &$crate::thread::Thread) -> $crate::thread::Status {
                $crate::api::VmFunction::unpack_and_call(
                    &primitive_cast!($arg_count, $func),
                    thread,
                )
            }
            $crate::api::primitive_f($name, wrapper, primitive_cast!($arg_count, $func))
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! field_decl_inner {
    () => {
    };

    ($field: ident) => {
        field_decl_inner!{
            ($field stringify!($field))
        }
    };
    (($alias: ident $field: expr)) => {
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $alias;
        impl $crate::api::record::Field for $alias {
            fn name() -> &'static str {
                $field
            }
        }
    };

    (type $field: ident $($args: ident)*) => {
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $field;
        impl $crate::api::record::Field for $field {
            fn name() -> &'static str {
                stringify!($field)
            }
            fn args() -> &'static [&'static str] {
                &[$(stringify!($args)),*]
            }
        }
    };

    ($field: ident, $($rest: tt)*) => {
        field_decl_inner!{
            ($field stringify!($field)),
            $($rest)*
        }
    };
    (($alias: ident $field: expr), $($rest: tt)*) => {
        field_decl_inner!{ ($alias $field) }
        field_decl_inner!{$($rest)*}
    };
    (type $alias: ident $($arg: ident)*, $($rest: tt)*) => {
        field_decl_inner!{ type $alias $($arg)* }
        field_decl_inner!{$($rest)*}
    }
}

/// Declares fields useable by the record macros
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
///
/// field_decl! {x, y}
/// ```
#[macro_export]
macro_rules! field_decl {
    ($($tt: tt)*) => {
        mod _field { field_decl_inner!($($tt)*); }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! field_decl_record {
    ([$($acc: tt)*]) => {
        field_decl!($($acc)*);
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($field stringify!($field)),]
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
        }
    };
    ([ $($acc: tt)* ] type $alias: ident $($arg: ident)* => $ignore: ty) => {
        field_decl_record!{
            [$($acc)* type $alias $($arg)*,]
        }
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($field stringify!($field)),]
            $($rest)*
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
            $($rest)*
        }
    };
    ([ $($acc: tt)* ] type $field: ident $($arg: ident)* => $ignore: ty, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* type $field $($arg)*,]
            $($rest)*
        }
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_no_decl_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, $value), record_no_decl_inner!())
    };
    ( ($field: ident $ignore: expr) => $value: expr) => {
        record_no_decl_inner!($field => $value)
    };
    ( type $field: ident $($arg: ident)* => $value: ty) => {
        record_no_decl_inner!()
    };

    ($field: ident => $value: expr, $($rest: tt)*) => {
        $crate::frunk_core::hlist::h_cons(
            (_field::$field, $value),
            record_no_decl_inner!($($rest)*)
        )
    };
    ( ($field: ident $ignore: expr) => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner!($field => $value, $($rest)*)
    };
    ( type $field: ident $($arg: ident)* => $value: ty, $($rest: tt)*) => {
        record_no_decl_inner!($($rest)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_no_decl_inner_types {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        record_no_decl_inner_types!()
    };
    ( ($field: ident $ignore: expr) => $value: expr) => {
        record_no_decl_inner_types!($field => $value)
    };
    ( type $field: ident $($arg: ident)* => $value: ty) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, ::std::marker::PhantomData::<$value>), record_no_decl_inner_types!())
    };

    ($field: ident => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner_types!($($rest)*)
    };
    ( ($field: ident $ignore: expr) => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner_types!($field => $value, $($rest)*)
    };
    ( type $field: ident $($arg: ident)* => $value: ty, $($rest: tt)*) => {
        $crate::frunk_core::hlist::h_cons(
            (_field::$field, ::std::marker::PhantomData::<$value>),
            record_no_decl_inner_types!($($rest)*)
        )
    };
}

/// Macro that creates a record that can be passed to gluon. Reuses already declared fields
/// instead of generating unique ones.
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
///
/// field_decl! {x, y, name}
///
/// fn main() {
///     record_no_decl!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record_no_decl {
    ($($tt: tt)*) => {
        {
            $crate::api::Record {
                type_fields: record_no_decl_inner_types!($($tt)*),
                fields: record_no_decl_inner!($($tt)*),
            }
        }
    }
}

/// Macro that creates a record that can be passed to gluon
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     record!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export]
macro_rules! record {
    ($($tt: tt)*) => {{
        field_decl_record!([] $($tt)*);
        record_no_decl!($($tt)*)
    }}
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_type_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: ty) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value), record_type_inner!()>
    };
    ($field: ident => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    };
    (type $field: ident $($arg: ident)* => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    }
}

#[macro_export]
macro_rules! row_type {
    ($($field: ident => $value: ty),*) => {
        row_type!($($field => $value),* | $crate::api::record::EmptyRow)
    };
    ($($field: ident => $value: ty),* | $rest: ty) => {
        $crate::api::record::Row<
            $crate::frunk_core::hlist::HNil,
            record_type_inner!($($field => $value),*),
            $rest,
        >
    }
}

/// Creates a Rust type compatible with the type of `record_no_decl!`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
/// // Fields used in `record_type!` needs to be forward declared
/// field_decl! {x, y}
/// fn new_vec(x: f64, y: f64) -> record_type!(x => f64, y => f64) {
///     record_no_decl!(x => y, y => y)
/// }
/// ```
#[macro_export]
macro_rules! record_type {
    ($($field: ident => $value: ty),*) => {
        $crate::api::Record<
            $crate::frunk_core::hlist::HNil,
            record_type_inner!($($field => $value),*)
            >
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! record_p_impl {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: pat) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field), tail: record_p_impl!() }
    };
    ($field: pat, $($field_tail: pat),*) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field),
                                           tail: record_p_impl!($($field_tail),*) }
    }
}

/// Creates a pattern which matches on marshalled gluon records
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     match record!(x => 1, y => "y") {
///         record_p!(a, "y") => assert_eq!(a, 1),
///         _ => assert!(false),
///     }
/// }
/// ```
#[macro_export]
macro_rules! record_p {
    ($($field: pat),*) => {
        $crate::api::Record {
            fields: record_p_impl!($($field),*),
            type_fields: _
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::api::VmType;
    use crate::thread::RootedThread;

    fn type_for<T: VmType>(_: &T) -> String {
        let vm = RootedThread::new();
        T::make_type(&vm).to_string()
    }

    #[test]
    fn record_type_field() {
        use crate::api::generic::{A, B};
        assert_eq!(type_for(&record!(type Test => i32)), "{ Test = Int }");
        assert_eq!(
            type_for(&record!(type Pair a b => (A, B))),
            "{ Pair a b = (a, b) }"
        );
    }
}
<commit_msg>fix: macro resolution in 2018 by adding `local_inner_macros`<commit_after>#[doc(hidden)]
#[macro_export]
macro_rules! primitive_cast {
    (0, $name:expr) => {
        $name as fn() -> _
    };
    (1, $name:expr) => {
        $name as fn(_) -> _
    };
    (2, $name:expr) => {
        $name as fn(_, _) -> _
    };
    (3, $name:expr) => {
        $name as fn(_, _, _) -> _
    };
    (4, $name:expr) => {
        $name as fn(_, _, _, _) -> _
    };
    (5, $name:expr) => {
        $name as fn(_, _, _, _, _) -> _
    };
    (6, $name:expr) => {
        $name as fn(_, _, _, _, _, _) -> _
    };
    (7, $name:expr) => {
        $name as fn(_, _, _, _, _, _, _) -> _
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! closure_wrapper {
    (0, $name:expr) => {
        || $crate::api::FutureResult::new($name())
    };
    (1, $name:expr) => {
        |a| $crate::api::FutureResult::new($name(a))
    };
    (2, $name:expr) => {
        |a, b| $crate::api::FutureResult::new($name(a, b))
    };
    (3, $name:expr) => {
        |a, b, c| $crate::api::FutureResult::new($name(a, b, c))
    };
    (4, $name:expr) => {
        |a, b, c, d| $crate::api::FutureResult::new($name(a, b, c, d))
    };
    (5, $name:expr) => {
        |a, b, c, d, e| $crate::api::FutureResult::new($name(a, b, c, d, e))
    };
    (6, $name:expr) => {
        |a, b, c, d, e, f| $crate::api::FutureResult::new($name(a, b, c, d, e, f))
    };
    (7, $name:expr) => {
        |a, b, c, d, e, f, g| $crate::api::FutureResult::new($name(a, b, c, d, e, f, g))
    };
}

/// Creates a `GluonFunction` from a function implementing `VMFunction`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn test(_x: i32, _y: String) -> f64 {
///     panic!()
/// }
///
/// fn main() {
///     primitive!(2, test);
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! primitive {
    ($arg_count:tt, async fn $name:expr) => {
        primitive!($arg_count, stringify_inner!($name), async fn $name)
    };

    ($arg_count:tt, $name:expr) => {
        primitive!($arg_count, stringify_inner!($name), $name)
    };
    ($arg_count:tt, $name:expr, async fn $func:expr) => {
        primitive!($arg_count, $name, closure_wrapper!($arg_count, $func))
    };
    ($arg_count:tt, $name:expr, $func:expr) => {
        unsafe {
            extern "C" fn wrapper(thread: &$crate::thread::Thread) -> $crate::thread::Status {
                $crate::api::VmFunction::unpack_and_call(
                    &primitive_cast!($arg_count, $func),
                    thread,
                )
            }
            $crate::api::primitive_f($name, wrapper, primitive_cast!($arg_count, $func))
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! stringify_inner {
    ($name:expr) => {
        stringify!($name)
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! field_decl_inner {
    () => {
    };

    ($field: ident) => {
        field_decl_inner!{
            ($field stringify_inner!($field))
        }
    };
    (($alias: ident $field: expr)) => {
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $alias;
        impl $crate::api::record::Field for $alias {
            fn name() -> &'static str {
                $field
            }
        }
    };

    (type $field: ident $($args: ident)*) => {
        #[allow(non_camel_case_types)]
        #[derive(Default)]
        pub struct $field;
        impl $crate::api::record::Field for $field {
            fn name() -> &'static str {
                stringify_inner!($field)
            }
            fn args() -> &'static [&'static str] {
                &[$(stringify_inner!($args)),*]
            }
        }
    };

    ($field: ident, $($rest: tt)*) => {
        field_decl_inner!{
            ($field stringify_inner!($field)),
            $($rest)*
        }
    };
    (($alias: ident $field: expr), $($rest: tt)*) => {
        field_decl_inner!{ ($alias $field) }
        field_decl_inner!{$($rest)*}
    };
    (type $alias: ident $($arg: ident)*, $($rest: tt)*) => {
        field_decl_inner!{ type $alias $($arg)* }
        field_decl_inner!{$($rest)*}
    }
}

/// Declares fields useable by the record macros
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
///
/// field_decl! {x, y}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! field_decl {
    ($($tt: tt)*) => {
        mod _field { field_decl_inner!($($tt)*); }
    }
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! field_decl_record {
    ([$($acc: tt)*]) => {
        field_decl!($($acc)*);
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($field stringify_inner!($field)),]
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
        }
    };
    ([ $($acc: tt)* ] type $alias: ident $($arg: ident)* => $ignore: ty) => {
        field_decl_record!{
            [$($acc)* type $alias $($arg)*,]
        }
    };

    ([ $($acc: tt)* ] $field: ident => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($field stringify_inner!($field)),]
            $($rest)*
        }
    };
    ([ $($acc: tt)* ] ($alias: ident $field: expr) => $ignore: expr, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* ($alias $field),]
            $($rest)*
        }
    };
    ([ $($acc: tt)* ] type $field: ident $($arg: ident)* => $ignore: ty, $($rest: tt)*) => {
        field_decl_record!{
            [$($acc)* type $field $($arg)*,]
            $($rest)*
        }
    }
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! record_no_decl_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, $value), record_no_decl_inner!())
    };
    ( ($field: ident $ignore: expr) => $value: expr) => {
        record_no_decl_inner!($field => $value)
    };
    ( type $field: ident $($arg: ident)* => $value: ty) => {
        record_no_decl_inner!()
    };

    ($field: ident => $value: expr, $($rest: tt)*) => {
        $crate::frunk_core::hlist::h_cons(
            (_field::$field, $value),
            record_no_decl_inner!($($rest)*)
        )
    };
    ( ($field: ident $ignore: expr) => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner!($field => $value, $($rest)*)
    };
    ( type $field: ident $($arg: ident)* => $value: ty, $($rest: tt)*) => {
        record_no_decl_inner!($($rest)*)
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! record_no_decl_inner_types {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: expr) => {
        record_no_decl_inner_types!()
    };
    ( ($field: ident $ignore: expr) => $value: expr) => {
        record_no_decl_inner_types!($field => $value)
    };
    ( type $field: ident $($arg: ident)* => $value: ty) => {
        $crate::frunk_core::hlist::h_cons((_field::$field, ::std::marker::PhantomData::<$value>), record_no_decl_inner_types!())
    };

    ($field: ident => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner_types!($($rest)*)
    };
    ( ($field: ident $ignore: expr) => $value: expr, $($rest: tt)*) => {
        record_no_decl_inner_types!($field => $value, $($rest)*)
    };
    ( type $field: ident $($arg: ident)* => $value: ty, $($rest: tt)*) => {
        $crate::frunk_core::hlist::h_cons(
            (_field::$field, ::std::marker::PhantomData::<$value>),
            record_no_decl_inner_types!($($rest)*)
        )
    };
}

/// Macro that creates a record that can be passed to gluon. Reuses already declared fields
/// instead of generating unique ones.
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
///
/// field_decl! {x, y, name}
///
/// fn main() {
///     record_no_decl!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! record_no_decl {
    ($($tt: tt)*) => {
        {
            $crate::api::Record {
                type_fields: record_no_decl_inner_types!($($tt)*),
                fields: record_no_decl_inner!($($tt)*),
            }
        }
    }
}

/// Macro that creates a record that can be passed to gluon
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     record!(x => 1, y => 2, name => "Gluon");
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! record {
    ($($tt: tt)*) => {{
        field_decl_record!([] $($tt)*);
        record_no_decl!($($tt)*)
    }}
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! record_type_inner {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: ident => $value: ty) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value), record_type_inner!()>
    };
    ($field: ident => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    };
    (type $field: ident $($arg: ident)* => $value: ty, $($field_tail: ident => $value_tail: ty),*) => {
        $crate::frunk_core::hlist::HCons<(_field::$field, $value),
                                record_type_inner!( $($field_tail => $value_tail),*)>
    }
}

#[macro_export(local_inner_macros)]
macro_rules! row_type {
    ($($field: ident => $value: ty),*) => {
        row_type!($($field => $value),* | $crate::api::record::EmptyRow)
    };
    ($($field: ident => $value: ty),* | $rest: ty) => {
        $crate::api::record::Row<
            $crate::frunk_core::hlist::HNil,
            record_type_inner!($($field => $value),*),
            $rest,
        >
    }
}

/// Creates a Rust type compatible with the type of `record_no_decl!`
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// # fn main() { }
/// // Fields used in `record_type!` needs to be forward declared
/// field_decl! {x, y}
/// fn new_vec(x: f64, y: f64) -> record_type!(x => f64, y => f64) {
///     record_no_decl!(x => y, y => y)
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! record_type {
    ($($field: ident => $value: ty),*) => {
        $crate::api::Record<
            $crate::frunk_core::hlist::HNil,
            record_type_inner!($($field => $value),*)
            >
    }
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! record_p_impl {
    () => { $crate::frunk_core::hlist::HNil };
    ($field: pat) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field), tail: record_p_impl!() }
    };
    ($field: pat, $($field_tail: pat),*) => {
        $crate::frunk_core::hlist::HCons { head: (_, $field),
                                           tail: record_p_impl!($($field_tail),*) }
    }
}

/// Creates a pattern which matches on marshalled gluon records
///
/// ```rust
/// #[macro_use]
/// extern crate gluon_vm;
/// fn main() {
///     match record!(x => 1, y => "y") {
///         record_p!(a, "y") => assert_eq!(a, 1),
///         _ => assert!(false),
///     }
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! record_p {
    ($($field: pat),*) => {
        $crate::api::Record {
            fields: record_p_impl!($($field),*),
            type_fields: _
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::api::VmType;
    use crate::thread::RootedThread;

    fn type_for<T: VmType>(_: &T) -> String {
        let vm = RootedThread::new();
        T::make_type(&vm).to_string()
    }

    #[test]
    fn record_type_field() {
        use crate::api::generic::{A, B};
        assert_eq!(type_for(&record!(type Test => i32)), "{ Test = Int }");
        assert_eq!(
            type_for(&record!(type Pair a b => (A, B))),
            "{ Pair a b = (a, b) }"
        );
    }
}
<|endoftext|>


<commit_before>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 };
use core::semantic::ast::*;
use core::position::*;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([
                        self.parser(MnEnv::parse_def)
                    ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }

}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<commit_msg>Start on adding form stubs to expr parser<commit_after>extern crate combine;
extern crate combine_language;
extern crate mnemosyne as core;

use combine::*;
use combine_language::{ LanguageEnv
                      , LanguageDef
                      , Identifier
                      };
use combine::primitives::{ Stream
                         , Positioner
                         , SourcePosition
                         };

use core::semantic::*;
use core::semantic::annotations::{ Annotated
                                 , UnscopedState
                                 };
use core::semantic::ast::*;
use core::position::*;

type ParseFn<'a, I, T> = fn (&MnEnv<'a, I>, State<I>) -> ParseResult<T, I>;

type U = UnscopedState;

/// Wraps a parsing function with a language definition environment.
///
/// TODO: this could probably push identifiers to the symbol table here?
#[derive(Copy)]
struct MnParser<'a: 'b, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b {
        env: &'b MnEnv<'a, I>
      , parser: ParseFn<'a, I, T>
}

impl<'a, 'b, I, T> Clone for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    fn clone(&self) -> Self {
        MnParser { env: self.env , parser: self.parser }
    }
}

impl<'a, 'b, I, T> Parser for MnParser<'a, 'b, I, T>
where I: Stream<Item=char>
    , I::Range: 'b
    , I: 'b
    , 'a: 'b {

    type Input = I;
    type Output = T;

    fn parse_state(&mut self, input: State<I>) -> ParseResult<T, I> {
        (self.parser)(self.env, input)
    }

}

struct MnEnv<'a, I>
where I: Stream<Item = char>
    , I::Item: Positioner<Position = SourcePosition> {
    env: LanguageEnv<'a, I>
}

impl <'a, I> std::ops::Deref for MnEnv<'a, I>
where I: Stream<Item=char> {
    type Target = LanguageEnv<'a, I>;
    fn deref(&self) -> &LanguageEnv<'a, I> { &self.env }
}

impl<'a, 'b, I> MnEnv<'a, I>
where I: Stream<Item=char>
    , I::Item: Positioner<Position = SourcePosition>
    , I::Range: 'b {

        /// Wrap a function into a MnParser with this environment
        fn parser<T>(&'b self, parser: ParseFn<'a, I, T>)
                    -> MnParser<'a, 'b, I, T> {
            MnParser { env: self, parser: parser }
        }

        fn parse_def(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_if(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_lambda(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_let(&self, input: State<I>) -> ParseResult<Form<'a, U>, I> {
            unimplemented!()
        }

        fn parse_expr(&self, input: State<I>) -> ParseResult<Expr<'a, U>, I> {
            let pos = Position::from(input.position.clone());
            self.env
                .parens(choice([ self.parser(MnEnv::parse_def)
                               , self.parser(MnEnv::parse_if)
                               , self.parser(MnEnv::parse_lambda)
                               , self.parser(MnEnv::parse_let)
                               ]))
                .map(|f| Annotated::new(f, pos) )
                .parse_state(input)
        }

        fn expr(&'b self) -> MnParser<'a, 'b, I, Expr<'a, U>> {
            self.parser(MnEnv::parse_expr)
        }

        fn def(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }

        fn if_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }

        fn let_form(&'b self) -> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }

        fn lambda(&'b self)-> MnParser<'a, 'b, I, Form<'a, U>> {
            unimplemented!()
        }
}
pub fn parse_module<N: ?Sized>(code: &str) -> Result<Vec<N>, ParseError<&str>>
where N: ASTNode + Sized {
    let alpha_ext = "+-*/<=>!?:$%_~^";
    let ops = "+-*/|=<>";
    let env = LanguageEnv::new(LanguageDef {
        ident: Identifier {
            start: letter().or(satisfy(|c| alpha_ext.contains(c)))
          , rest: alpha_num().or(satisfy(|c| alpha_ext.contains(c)))
          , reserved: [ "and"               , "begin"
                      , "case"              , "cond"
                      , "data"              , "define"
                      , "defn"              , "delay"
                      , "do"                , "else"
                      , "if"                , "lambda"
                      , "let"               , "let*"
                      , "letrec"            , "or"
                      , "quasiquote"        , "quote"
                      , "set!"              , "unquote"
                      , "unquote-splicing"
                      ].iter().map(|x| (*x).into()).collect()
        }
      , op: Identifier {
            start: satisfy(|c| ops.contains(c))
          , rest:  satisfy(|c| ops.contains(c))
          , reserved: [ "=>", "->", "\\", "|"].iter().map(|x| (*x).into())
                                                     .collect()
        }
      , comment_line: string(";").map(|_| ())
      , comment_start: string("#|").map(|_| ())
      , comment_end: string("|#").map(|_| ())
    });
    let env = MnEnv { env: env };

    env.white_space()
       .parse(code);

    unimplemented!()
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fmt::{self, Display};

use base::{Event, RawDescriptor};
use hypervisor::Datamatch;
use resources::{Error as SystemAllocatorFaliure, SystemAllocator};

use crate::pci::pci_configuration;
use crate::pci::{PciAddress, PciInterruptPin};
use crate::{BusAccessInfo, BusDevice};
use crate::virtio::snd::vios_backend::Error as VioSError;

#[derive(Debug)]
pub enum Error {
    /// Setup of the device capabilities failed.
    CapabilitiesSetup(pci_configuration::Error),
    /// Allocating space for an IO BAR failed.
    IoAllocationFailed(u64, SystemAllocatorFaliure),
    /// Registering an IO BAR failed.
    IoRegistrationFailed(u64, pci_configuration::Error),
    /// Create cras client failed.
    #[cfg(feature = "audio")]
    CreateCrasClientFailed(libcras::Error),
    /// Create VioS client failed.
    #[cfg(feature = "audio")]
    CreateViosClientFailed(VioSError),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
            #[cfg(feature = "audio")]
            CreateCrasClientFailed(e) => write!(f, "failed to create CRAS Client: {}", e),
            #[cfg(feature = "audio")]
            CreateViosClientFailed(e) => write!(f, "failed to create VioS Client: {}", e),
            IoAllocationFailed(size, e) => write!(
                f,
                "failed to allocate space for an IO BAR, size={}: {}",
                size, e
            ),
            IoRegistrationFailed(addr, e) => {
                write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
            }
        }
    }
}

pub trait PciDevice: Send {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String;
    /// Assign a unique bus, device and function number to this device.
    fn assign_address(&mut self, _address: PciAddress) {}
    /// A vector of device-specific file descriptors that must be kept open
    /// after jailing. Must be called before the process is jailed.
    fn keep_rds(&self) -> Vec<RawDescriptor>;
    /// Assign a legacy PCI IRQ to this device.
    /// The device may write to `irq_evt` to trigger an interrupt.
    /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary.
    fn assign_irq(
        &mut self,
        _irq_evt: Event,
        _irq_resample_evt: Event,
        _irq_num: u32,
        _irq_pin: PciInterruptPin,
    ) {
    }
    /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
    /// returns an address. Returns a Vec of (address, length) tuples.
    fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        Ok(Vec::new())
    }

    /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples.
    /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
    /// - these BARs represent normal memory.
    fn allocate_device_bars(
        &mut self,
        _resources: &mut SystemAllocator,
    ) -> Result<Vec<(u64, u64)>> {
        Ok(Vec::new())
    }

    /// Register any capabilties specified by the device.
    fn register_device_capabilities(&mut self) -> Result<()> {
        Ok(())
    }

    /// Gets a list of ioevents that should be registered with the running VM. The list is
    /// returned as a Vec of (event, addr, datamatch) tuples.
    fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> {
        Vec::new()
    }

    /// Reads from a PCI configuration register.
    /// * `reg_idx` - PCI register index (in units of 4 bytes).
    fn read_config_register(&self, reg_idx: usize) -> u32;

    /// Writes to a PCI configuration register.
    /// * `reg_idx` - PCI register index (in units of 4 bytes).
    /// * `offset`  - byte offset within 4-byte register.
    /// * `data`    - The data to write.
    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]);

    /// Reads from a BAR region mapped in to the device.
    /// * `addr` - The guest address inside the BAR.
    /// * `data` - Filled with the data from `addr`.
    fn read_bar(&mut self, addr: u64, data: &mut [u8]);
    /// Writes to a BAR region mapped in to the device.
    /// * `addr` - The guest address inside the BAR.
    /// * `data` - The data to write.
    fn write_bar(&mut self, addr: u64, data: &[u8]);
    /// Invoked when the device is sandboxed.
    fn on_device_sandboxed(&mut self) {}
}

impl<T: PciDevice> BusDevice for T {
    fn debug_label(&self) -> String {
        PciDevice::debug_label(self)
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        self.read_bar(info.address, data)
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        self.write_bar(info.address, data)
    }

    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        if offset as usize + data.len() > 4 {
            return;
        }

        self.write_config_register(reg_idx, offset, data)
    }

    fn config_register_read(&self, reg_idx: usize) -> u32 {
        self.read_config_register(reg_idx)
    }

    fn on_sandboxed(&mut self) {
        self.on_device_sandboxed();
    }
}

impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String {
        (**self).debug_label()
    }
    fn assign_address(&mut self, address: PciAddress) {
        (**self).assign_address(address)
    }
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        (**self).keep_rds()
    }
    fn assign_irq(
        &mut self,
        irq_evt: Event,
        irq_resample_evt: Event,
        irq_num: u32,
        irq_pin: PciInterruptPin,
    ) {
        (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin)
    }
    fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        (**self).allocate_io_bars(resources)
    }
    fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        (**self).allocate_device_bars(resources)
    }
    fn register_device_capabilities(&mut self) -> Result<()> {
        (**self).register_device_capabilities()
    }
    fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> {
        (**self).ioevents()
    }
    fn read_config_register(&self, reg_idx: usize) -> u32 {
        (**self).read_config_register(reg_idx)
    }
    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        (**self).write_config_register(reg_idx, offset, data)
    }
    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
        (**self).read_bar(addr, data)
    }
    fn write_bar(&mut self, addr: u64, data: &[u8]) {
        (**self).write_bar(addr, data)
    }
    /// Invoked when the device is sandboxed.
    fn on_device_sandboxed(&mut self) {
        (**self).on_device_sandboxed()
    }
}
<commit_msg>devices: fix build with audio feature disabled<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fmt::{self, Display};

use base::{Event, RawDescriptor};
use hypervisor::Datamatch;
use resources::{Error as SystemAllocatorFaliure, SystemAllocator};

use crate::pci::pci_configuration;
use crate::pci::{PciAddress, PciInterruptPin};
use crate::{BusAccessInfo, BusDevice};
#[cfg(feature = "audio")]
use crate::virtio::snd::vios_backend::Error as VioSError;

#[derive(Debug)]
pub enum Error {
    /// Setup of the device capabilities failed.
    CapabilitiesSetup(pci_configuration::Error),
    /// Allocating space for an IO BAR failed.
    IoAllocationFailed(u64, SystemAllocatorFaliure),
    /// Registering an IO BAR failed.
    IoRegistrationFailed(u64, pci_configuration::Error),
    /// Create cras client failed.
    #[cfg(feature = "audio")]
    CreateCrasClientFailed(libcras::Error),
    /// Create VioS client failed.
    #[cfg(feature = "audio")]
    CreateViosClientFailed(VioSError),
}
pub type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            CapabilitiesSetup(e) => write!(f, "failed to add capability {}", e),
            #[cfg(feature = "audio")]
            CreateCrasClientFailed(e) => write!(f, "failed to create CRAS Client: {}", e),
            #[cfg(feature = "audio")]
            CreateViosClientFailed(e) => write!(f, "failed to create VioS Client: {}", e),
            IoAllocationFailed(size, e) => write!(
                f,
                "failed to allocate space for an IO BAR, size={}: {}",
                size, e
            ),
            IoRegistrationFailed(addr, e) => {
                write!(f, "failed to register an IO BAR, addr={} err={}", addr, e)
            }
        }
    }
}

pub trait PciDevice: Send {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String;
    /// Assign a unique bus, device and function number to this device.
    fn assign_address(&mut self, _address: PciAddress) {}
    /// A vector of device-specific file descriptors that must be kept open
    /// after jailing. Must be called before the process is jailed.
    fn keep_rds(&self) -> Vec<RawDescriptor>;
    /// Assign a legacy PCI IRQ to this device.
    /// The device may write to `irq_evt` to trigger an interrupt.
    /// When `irq_resample_evt` is signaled, the device should re-assert `irq_evt` if necessary.
    fn assign_irq(
        &mut self,
        _irq_evt: Event,
        _irq_resample_evt: Event,
        _irq_num: u32,
        _irq_pin: PciInterruptPin,
    ) {
    }
    /// Allocates the needed IO BAR space using the `allocate` function which takes a size and
    /// returns an address. Returns a Vec of (address, length) tuples.
    fn allocate_io_bars(&mut self, _resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        Ok(Vec::new())
    }

    /// Allocates the needed device BAR space. Returns a Vec of (address, length) tuples.
    /// Unlike MMIO BARs (see allocate_io_bars), device BARs are not expected to incur VM exits
    /// - these BARs represent normal memory.
    fn allocate_device_bars(
        &mut self,
        _resources: &mut SystemAllocator,
    ) -> Result<Vec<(u64, u64)>> {
        Ok(Vec::new())
    }

    /// Register any capabilties specified by the device.
    fn register_device_capabilities(&mut self) -> Result<()> {
        Ok(())
    }

    /// Gets a list of ioevents that should be registered with the running VM. The list is
    /// returned as a Vec of (event, addr, datamatch) tuples.
    fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> {
        Vec::new()
    }

    /// Reads from a PCI configuration register.
    /// * `reg_idx` - PCI register index (in units of 4 bytes).
    fn read_config_register(&self, reg_idx: usize) -> u32;

    /// Writes to a PCI configuration register.
    /// * `reg_idx` - PCI register index (in units of 4 bytes).
    /// * `offset`  - byte offset within 4-byte register.
    /// * `data`    - The data to write.
    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]);

    /// Reads from a BAR region mapped in to the device.
    /// * `addr` - The guest address inside the BAR.
    /// * `data` - Filled with the data from `addr`.
    fn read_bar(&mut self, addr: u64, data: &mut [u8]);
    /// Writes to a BAR region mapped in to the device.
    /// * `addr` - The guest address inside the BAR.
    /// * `data` - The data to write.
    fn write_bar(&mut self, addr: u64, data: &[u8]);
    /// Invoked when the device is sandboxed.
    fn on_device_sandboxed(&mut self) {}
}

impl<T: PciDevice> BusDevice for T {
    fn debug_label(&self) -> String {
        PciDevice::debug_label(self)
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        self.read_bar(info.address, data)
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        self.write_bar(info.address, data)
    }

    fn config_register_write(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        if offset as usize + data.len() > 4 {
            return;
        }

        self.write_config_register(reg_idx, offset, data)
    }

    fn config_register_read(&self, reg_idx: usize) -> u32 {
        self.read_config_register(reg_idx)
    }

    fn on_sandboxed(&mut self) {
        self.on_device_sandboxed();
    }
}

impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
    /// Returns a label suitable for debug output.
    fn debug_label(&self) -> String {
        (**self).debug_label()
    }
    fn assign_address(&mut self, address: PciAddress) {
        (**self).assign_address(address)
    }
    fn keep_rds(&self) -> Vec<RawDescriptor> {
        (**self).keep_rds()
    }
    fn assign_irq(
        &mut self,
        irq_evt: Event,
        irq_resample_evt: Event,
        irq_num: u32,
        irq_pin: PciInterruptPin,
    ) {
        (**self).assign_irq(irq_evt, irq_resample_evt, irq_num, irq_pin)
    }
    fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        (**self).allocate_io_bars(resources)
    }
    fn allocate_device_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> {
        (**self).allocate_device_bars(resources)
    }
    fn register_device_capabilities(&mut self) -> Result<()> {
        (**self).register_device_capabilities()
    }
    fn ioevents(&self) -> Vec<(&Event, u64, Datamatch)> {
        (**self).ioevents()
    }
    fn read_config_register(&self, reg_idx: usize) -> u32 {
        (**self).read_config_register(reg_idx)
    }
    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
        (**self).write_config_register(reg_idx, offset, data)
    }
    fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
        (**self).read_bar(addr, data)
    }
    fn write_bar(&mut self, addr: u64, data: &[u8]) {
        (**self).write_bar(addr, data)
    }
    /// Invoked when the device is sandboxed.
    fn on_device_sandboxed(&mut self) {
        (**self).on_device_sandboxed()
    }
}
<|endoftext|>


<commit_before>//! Known Ethereum 2.0 clients and their fingerprints.
//!
//! Currently using identify to fingerprint.

use libp2p::identify::IdentifyInfo;
use serde::Serialize;

/// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
pub struct Client {
    /// The client's name (Ex: lighthouse, prism, nimbus, etc)
    pub kind: ClientKind,
    /// The client's version.
    pub version: String,
    /// The OS version of the client.
    pub os_version: String,
    /// The libp2p protocol version.
    pub protocol_version: String,
    /// Identify agent string
    pub agent_string: Option<String>,
}

#[derive(Clone, Debug, Serialize)]
pub enum ClientKind {
    /// A lighthouse node (the best kind).
    Lighthouse,
    /// A Nimbus node.
    Nimbus,
    /// A Teku node.
    Teku,
    /// A Prysm node.
    Prysm,
    /// An unknown client.
    Unknown,
}

impl Default for Client {
    fn default() -> Self {
        Client {
            kind: ClientKind::Unknown,
            version: "unknown".into(),
            os_version: "unknown".into(),
            protocol_version: "unknown".into(),
            agent_string: None,
        }
    }
}

impl Client {
    /// Builds a `Client` from `IdentifyInfo`.
    pub fn from_identify_info(info: &IdentifyInfo) -> Self {
        let (kind, version, os_version) = client_from_agent_version(&info.agent_version);

        Client {
            kind,
            version,
            os_version,
            protocol_version: info.protocol_version.clone(),
            agent_string: Some(info.agent_version.clone()),
        }
    }
}

impl std::fmt::Display for Client {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.kind {
            ClientKind::Lighthouse => write!(
                f,
                "Lighthouse: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Teku => write!(
                f,
                "Teku: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Nimbus => write!(
                f,
                "Nimbus: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Prysm => write!(
                f,
                "Prysm: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Unknown => {
                if let Some(agent_string) = &self.agent_string {
                    write!(f, "Unknown: {}", agent_string)
                } else {
                    write!(f, "Unknown")
                }
            }
        }
    }
}

// helper function to identify clients from their agent_version. Returns the client
// kind and it's associated version and the OS kind.
fn client_from_agent_version(agent_version: &str) -> (ClientKind, String, String) {
    let mut agent_split = agent_version.split('/');
    match agent_split.next() {
        Some("Lighthouse") => {
            let kind = ClientKind::Lighthouse;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("teku") => {
            let kind = ClientKind::Teku;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("github.com") => {
            let kind = ClientKind::Prysm;
            let unknown = String::from("unknown");
            (kind, unknown.clone(), unknown)
        }
        Some("Prysm") => {
            let kind = ClientKind::Prysm;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nim-libp2p") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        _ => {
            let unknown = String::from("unknown");
            (ClientKind::Unknown, unknown.clone(), unknown)
        }
    }
}
<commit_msg>Fingerprint Lodestar (#1536)<commit_after>//! Known Ethereum 2.0 clients and their fingerprints.
//!
//! Currently using identify to fingerprint.

use libp2p::identify::IdentifyInfo;
use serde::Serialize;

/// Various client and protocol information related to a node.
#[derive(Clone, Debug, Serialize)]
pub struct Client {
    /// The client's name (Ex: lighthouse, prism, nimbus, etc)
    pub kind: ClientKind,
    /// The client's version.
    pub version: String,
    /// The OS version of the client.
    pub os_version: String,
    /// The libp2p protocol version.
    pub protocol_version: String,
    /// Identify agent string
    pub agent_string: Option<String>,
}

#[derive(Clone, Debug, Serialize)]
pub enum ClientKind {
    /// A lighthouse node (the best kind).
    Lighthouse,
    /// A Nimbus node.
    Nimbus,
    /// A Teku node.
    Teku,
    /// A Prysm node.
    Prysm,
    /// A lodestar node.
    Lodestar,
    /// An unknown client.
    Unknown,
}

impl Default for Client {
    fn default() -> Self {
        Client {
            kind: ClientKind::Unknown,
            version: "unknown".into(),
            os_version: "unknown".into(),
            protocol_version: "unknown".into(),
            agent_string: None,
        }
    }
}

impl Client {
    /// Builds a `Client` from `IdentifyInfo`.
    pub fn from_identify_info(info: &IdentifyInfo) -> Self {
        let (kind, version, os_version) = client_from_agent_version(&info.agent_version);

        Client {
            kind,
            version,
            os_version,
            protocol_version: info.protocol_version.clone(),
            agent_string: Some(info.agent_version.clone()),
        }
    }
}

impl std::fmt::Display for Client {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.kind {
            ClientKind::Lighthouse => write!(
                f,
                "Lighthouse: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Teku => write!(
                f,
                "Teku: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Nimbus => write!(
                f,
                "Nimbus: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Prysm => write!(
                f,
                "Prysm: version: {}, os_version: {}",
                self.version, self.os_version
            ),
            ClientKind::Lodestar => write!(f, "Lodestar: version: {}", self.version),
            ClientKind::Unknown => {
                if let Some(agent_string) = &self.agent_string {
                    write!(f, "Unknown: {}", agent_string)
                } else {
                    write!(f, "Unknown")
                }
            }
        }
    }
}

// helper function to identify clients from their agent_version. Returns the client
// kind and it's associated version and the OS kind.
fn client_from_agent_version(agent_version: &str) -> (ClientKind, String, String) {
    let mut agent_split = agent_version.split('/');
    match agent_split.next() {
        Some("Lighthouse") => {
            let kind = ClientKind::Lighthouse;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("teku") => {
            let kind = ClientKind::Teku;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("github.com") => {
            let kind = ClientKind::Prysm;
            let unknown = String::from("unknown");
            (kind, unknown.clone(), unknown)
        }
        Some("Prysm") => {
            let kind = ClientKind::Prysm;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if agent_split.next().is_some() {
                if let Some(agent_version) = agent_split.next() {
                    version = agent_version.into();
                    if let Some(agent_os_version) = agent_split.next() {
                        os_version = agent_os_version.into();
                    }
                }
            }
            (kind, version, os_version)
        }
        Some("nim-libp2p") => {
            let kind = ClientKind::Nimbus;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        Some("js-libp2p") => {
            let kind = ClientKind::Lodestar;
            let mut version = String::from("unknown");
            let mut os_version = version.clone();
            if let Some(agent_version) = agent_split.next() {
                version = agent_version.into();
                if let Some(agent_os_version) = agent_split.next() {
                    os_version = agent_os_version.into();
                }
            }
            (kind, version, os_version)
        }
        _ => {
            let unknown = String::from("unknown");
            (ClientKind::Unknown, unknown.clone(), unknown)
        }
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;
use sourcemap;

use CliResult;

fn join_url(base_url: &str, url: &str) -> CliResult<String> {
    Ok(Url::parse(base_url)?.join(url)?.to_string())
}

#[derive(PartialEq)]
enum SourceType {
    Script,
    SourceMap,
}

#[derive(PartialEq, Debug)]
enum LogLevel {
    Info,
    Warning,
    Error,
}

impl LogLevel {
    fn is_insignificant(&self) -> bool {
        *self == LogLevel::Info
    }
}

struct Source {
    url: String,
    file_path: PathBuf,
    ty: SourceType,
}

pub struct SourceMapValidator {
    sources: HashMap<String, Source>,
    verbose: bool,
}

struct Log {
    pub failed: bool,
    last_source: Option<String>,
    verbose: bool,
}

impl Log {
    pub fn new(verbose: bool) -> Log {
        Log {
            failed: false,
            last_source: None,
            verbose: verbose,
        }
    }

    pub fn log(&mut self, source: &Source, level: LogLevel, message: String) {
        if self.last_source.as_ref() != Some(&source.url) {
            self.last_source = Some(source.url.clone());
            println!("  {}", source.url);
        }
        if level.is_insignificant() && !self.verbose {
            return;
        }
        println!("    {:?}: {}", level, &message);
        if level == LogLevel::Error {
            self.failed = true;
        }
    }

    pub fn error(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Error, message);
    }

    pub fn warn(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Warning, message);
    }

    pub fn info(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Info, message);
    }
}

impl SourceMapValidator {
    pub fn new(verbose: bool) -> SourceMapValidator {
        SourceMapValidator {
            sources: HashMap::new(),
            verbose: verbose,
        }
    }

    pub fn consider_file(&mut self, path: &Path, url: &str) -> bool {
        let ty = match path.extension().and_then(|x| x.to_str()) {
            Some("js") => SourceType::Script,
            Some("map") => SourceType::SourceMap,
            _ => { return false; }
        };
        self.sources.insert(url.to_owned(), Source {
            url: url.to_owned(),
            file_path: path.to_path_buf(),
            ty: ty,
        });
        true
    }

    fn validate_script(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        let reference = sourcemap::locate_sourcemap_reference(&f)?;
        if let sourcemap::SourceMapRef::LegacyRef(_) = reference {
            log.warn(source, "encountered a legacy reference".into());
        }
        if let Some(url) = reference.get_url() {
            let full_url = join_url(&source.url, url)?;
            log.info(source, format!("sourcemap at {}", full_url));
        } else {
            log.error(source, "missing sourcemap!".into());
        }
        Ok(())
    }

    fn validate_sourcemap(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        match sourcemap::decode(&f)? {
            sourcemap::DecodedMap::Regular(sm) => {
                for idx in 0..sm.get_source_count() {
                    let source_url = sm.get_source(idx).unwrap_or("??");
                    if sm.get_source_contents(idx).is_some() ||
                       self.sources.get(source_url).is_some() {
                        log.info(source, format!("found source ({})", source_url));
                    } else {
                        log.warn(source, format!("missing sourcecode ({})", source_url));
                    }
                }
            },
            sourcemap::DecodedMap::Index(_) => {
                log.warn(source, "encountered indexed sourcemap. We
                         cannot validate those.".into());
            }
        }
        Ok(())
    }

    pub fn validate_sources(&self) -> CliResult<()> {
        let mut log = Log::new(self.verbose);
        let mut sources : Vec<_> = self.sources.iter().map(|x| x.1).collect();
        sources.sort_by_key(|x| &x.url);

        for source in sources.iter() {
            if source.ty == SourceType::Script {
                if let Err(err) = self.validate_script(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            } else if source.ty == SourceType::SourceMap {
                if let Err(err) = self.validate_sourcemap(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            }
        }
        if log.failed {
            fail!("Encountered problems when validating sourcemaps.");
        }
        println!("All Good!");
        Ok(())
    }
}
<commit_msg>Do not error if non minimized files do not have a source reference<commit_after>use std::fs;
use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;
use sourcemap;

use CliResult;

fn join_url(base_url: &str, url: &str) -> CliResult<String> {
    Ok(Url::parse(base_url)?.join(url)?.to_string())
}

#[derive(PartialEq)]
enum SourceType {
    Script,
    SourceMap,
}

#[derive(PartialEq, Debug)]
enum LogLevel {
    Info,
    Warning,
    Error,
}

impl LogLevel {
    fn is_insignificant(&self) -> bool {
        *self == LogLevel::Info
    }
}

struct Source {
    url: String,
    file_path: PathBuf,
    ty: SourceType,
}

pub struct SourceMapValidator {
    sources: HashMap<String, Source>,
    verbose: bool,
}

struct Log {
    pub failed: bool,
    last_source: Option<String>,
    verbose: bool,
}

impl Log {
    pub fn new(verbose: bool) -> Log {
        Log {
            failed: false,
            last_source: None,
            verbose: verbose,
        }
    }

    pub fn log(&mut self, source: &Source, level: LogLevel, message: String) {
        if self.last_source.as_ref() != Some(&source.url) {
            self.last_source = Some(source.url.clone());
            println!("  {}", source.url);
        }
        if level.is_insignificant() && !self.verbose {
            return;
        }
        println!("    {:?}: {}", level, &message);
        if level == LogLevel::Error {
            self.failed = true;
        }
    }

    pub fn error(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Error, message);
    }

    pub fn warn(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Warning, message);
    }

    pub fn info(&mut self, source: &Source, message: String) {
        self.log(source, LogLevel::Info, message);
    }
}

impl SourceMapValidator {
    pub fn new(verbose: bool) -> SourceMapValidator {
        SourceMapValidator {
            sources: HashMap::new(),
            verbose: verbose,
        }
    }

    pub fn consider_file(&mut self, path: &Path, url: &str) -> bool {
        let ty = match path.extension().and_then(|x| x.to_str()) {
            Some("js") => SourceType::Script,
            Some("map") => SourceType::SourceMap,
            _ => { return false; }
        };
        self.sources.insert(url.to_owned(), Source {
            url: url.to_owned(),
            file_path: path.to_path_buf(),
            ty: ty,
        });
        true
    }

    fn validate_script(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        let reference = sourcemap::locate_sourcemap_reference(&f)?;
        if let sourcemap::SourceMapRef::LegacyRef(_) = reference {
            log.warn(source, "encountered a legacy reference".into());
        }
        if let Some(url) = reference.get_url() {
            let full_url = join_url(&source.url, url)?;
            log.info(source, format!("sourcemap at {}", full_url));
        } else if source.url.ends_with(".min.js") {
            log.error(source, "missing sourcemap!".into());
        } else {
            log.warn(source, "no sourcemap reference".into());
        }
        Ok(())
    }

    fn validate_sourcemap(&self, log: &mut Log, source: &Source) -> CliResult<()> {
        let f = fs::File::open(&source.file_path)?;
        match sourcemap::decode(&f)? {
            sourcemap::DecodedMap::Regular(sm) => {
                for idx in 0..sm.get_source_count() {
                    let source_url = sm.get_source(idx).unwrap_or("??");
                    if sm.get_source_contents(idx).is_some() ||
                       self.sources.get(source_url).is_some() {
                        log.info(source, format!("found source ({})", source_url));
                    } else {
                        log.warn(source, format!("missing sourcecode ({})", source_url));
                    }
                }
            },
            sourcemap::DecodedMap::Index(_) => {
                log.warn(source, "encountered indexed sourcemap. We
                         cannot validate those.".into());
            }
        }
        Ok(())
    }

    pub fn validate_sources(&self) -> CliResult<()> {
        let mut log = Log::new(self.verbose);
        let mut sources : Vec<_> = self.sources.iter().map(|x| x.1).collect();
        sources.sort_by_key(|x| &x.url);

        for source in sources.iter() {
            if source.ty == SourceType::Script {
                if let Err(err) = self.validate_script(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            } else if source.ty == SourceType::SourceMap {
                if let Err(err) = self.validate_sourcemap(&mut log, &source) {
                    log.error(&source, format!("failed to process: {}", err));
                }
            }
        }
        if log.failed {
            fail!("Encountered problems when validating sourcemaps.");
        }
        println!("All Good!");
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::terrain::tile_cache::LayerType;
use crate::terrain::tile_cache::{Priority, TileCache};
use byteorder::{ByteOrder, NativeEndian};
use cgmath::*;
use collision::{Frustum, Relation};
use std::collections::HashMap;

pub(crate) mod node;
pub(crate) mod render;

pub(crate) use crate::terrain::quadtree::node::*;
pub(crate) use crate::terrain::quadtree::render::*;

/// The central object in terra. It holds all relevant state and provides functions to update and
/// render the terrain.
pub(crate) struct QuadTree {
    // ocean: Ocean<R>,
    /// List of nodes that will be rendered.
    visible_nodes: Vec<VNode>,
    partially_visible_nodes: Vec<(VNode, u8)>,

    heights_resolution: u32,

    node_states: Vec<NodeState>,
}

impl std::fmt::Debug for QuadTree {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "QuadTree")
    }
}

#[allow(unused)]
impl QuadTree {
    pub(crate) fn new(heights_resolution: u32) -> Self {
        Self {
            visible_nodes: Vec::new(),
            partially_visible_nodes: Vec::new(),
            node_states: Vec::new(),
            heights_resolution,
        }
    }

    pub(crate) fn create_index_buffers(
        &self,
        device: &wgpu::Device,
    ) -> (wgpu::Buffer, wgpu::Buffer) {
        let make_index_buffer = |resolution: u16| -> wgpu::Buffer {
            let mapped = device.create_buffer_mapped(
                12 * (resolution as usize + 1) * (resolution as usize + 1),
                wgpu::BufferUsage::INDEX,
            );

            let mut i = 0;
            let width = resolution + 1;
            for y in 0..resolution {
                for x in 0..resolution {
                    for offset in [0, 1, width, 1, width + 1, width].iter() {
                        NativeEndian::write_u16(&mut mapped.data[i..], offset + (x + y * width));
                        i += 2;
                    }
                }
            }

            mapped.finish()
        };
        let resolution = self.heights_resolution as u16;

        (make_index_buffer(resolution), make_index_buffer(resolution / 2))
    }

    pub fn update_cache(&mut self, tile_cache: &mut TileCache, camera: mint::Point3<f32>) {
        let camera = Point3::new(camera.x, camera.y, camera.z);

        tile_cache.update_priorities(camera);

        VNode::breadth_first(|node| {
            let priority = node.priority(camera);
            if priority < Priority::cutoff() {
                return false;
            }

            tile_cache.add_missing((priority, node));

            if node.level() >= 19 {
                return false;
            }

            true
        });
    }

    pub fn update_visibility(
        &mut self,
        tile_cache: &TileCache,
        camera: mint::Point3<f32>,
        cull_frustum: Option<Frustum<f32>>,
    ) {
        let camera = Point3::new(camera.x, camera.y, camera.z);

        self.visible_nodes.clear();
        self.partially_visible_nodes.clear();

        let mut node_visibilities: HashMap<VNode, bool> = HashMap::new();

        // Any node with all needed layers in cache is visible...
        VNode::breadth_first(|node| {
            let visible = node == VNode::root() || node.priority(camera) >= Priority::cutoff();
            node_visibilities.insert(node, visible);
            visible
        });
        let min_missing_level = node_visibilities
            .iter()
            .filter(|(&n, &v)| v && !tile_cache.contains(n, LayerType::Displacements))
            .map(|(n, v)| n.level())
            .min();
        if let Some(min) = min_missing_level {
            for (n, v) in node_visibilities.iter_mut() {
                if n.level() >= min {
                    *v = false;
                }
            }
        }

        // ...Except if all its children are visible instead.
        VNode::breadth_first(|node| {
            if node_visibilities[&node] {
                let mut mask = 0;
                let mut has_visible_children = false;
                for (i, c) in node.children().iter().enumerate() {
                    if !node_visibilities[c] {
                        mask = mask | (1 << i);
                    }

                    if node_visibilities[&c] {
                        has_visible_children = true;
                    }
                }

                if let Some(frustum) = cull_frustum {
                    // TODO: Also try to cull parts of a node, if contains() returns Relation::Cross.
                    if frustum.contains(&node.bounds().as_aabb3()) == Relation::Out {
                        mask = 0;
                    }
                }

                if mask == 0 {
                    node_visibilities.insert(node, false);
                } else if has_visible_children {
                    self.partially_visible_nodes.push((node, mask));
                } else {
                    self.visible_nodes.push(node);
                }

                true
            } else {
                false
            }
        });
    }

    // pub fn get_height(
    //     &self,
    //     mapfile: &MapFile,
    //     tile_cache: &VecMap<TileCache>,
    //     p: Point2<f32>,
    // ) -> Option<f32> {
    //     if self.nodes[0].bounds.min.x > p.x
    //         || self.nodes[0].bounds.max.x < p.x
    //         || self.nodes[0].bounds.min.z > p.y
    //         || self.nodes[0].bounds.max.z < p.y
    //     {
    //         return None;
    //     }

    //     let mut id = NodeId::root();
    //     while self.nodes[id].children.iter().any(|c| c.is_some()) {
    //         for c in self.nodes[id].children.iter() {
    //             if let Some(c) = *c {
    //                 if self.nodes[c].bounds.min.x <= p.x
    //                     && self.nodes[c].bounds.max.x >= p.x
    //                     && self.nodes[c].bounds.min.z <= p.y
    //                     && self.nodes[c].bounds.max.z >= p.y
    //                 {
    //                     id = c;
    //                     break;
    //                 }
    //             }
    //         }
    //     }

    //     let layer = &tile_cache[LayerType::Heights.index()];
    //     let resolution = (layer.resolution() - 1) as f32;
    //     let x = (p.x - self.nodes[id].bounds.min.x) / self.nodes[id].side_length() * resolution;
    //     let y = (p.y - self.nodes[id].bounds.min.z) / self.nodes[id].side_length() * resolution;

    //     let get_texel =
    //         |x, y| layer.get_texel(mapfile, id, x, y).read_f32::<LittleEndian>().unwrap();

    //     let (mut fx, mut fy) = (x.fract(), y.fract());
    //     let (mut ix, mut iy) = (x.floor() as usize, y.floor() as usize);
    //     if ix == layer.resolution() as usize - 1 {
    //         ix = layer.resolution() as usize - 2;
    //         fx = 1.0;
    //     }
    //     if iy == layer.resolution() as usize - 1 {
    //         iy = layer.resolution() as usize - 2;
    //         fy = 1.0;
    //     }

    //     if fx + fy < 1.0 {
    //         Some(
    //             (1.0 - fx - fy) * get_texel(ix, iy)
    //                 + fx * get_texel(ix + 1, iy)
    //                 + fy * get_texel(ix, iy + 1),
    //         )
    //     } else {
    //         Some(
    //             (fx + fy - 1.0) * get_texel(ix + 1, iy + 1)
    //                 + (1.0 - fx) * get_texel(ix, iy + 1)
    //                 + (1.0 - fy) * get_texel(ix + 1, iy),
    //         )
    //     }
    // }
}
<commit_msg>More detailed quadtree levels<commit_after>use crate::terrain::tile_cache::LayerType;
use crate::terrain::tile_cache::{Priority, TileCache};
use byteorder::{ByteOrder, NativeEndian};
use cgmath::*;
use collision::{Frustum, Relation};
use std::collections::HashMap;

pub(crate) mod node;
pub(crate) mod render;

pub(crate) use crate::terrain::quadtree::node::*;
pub(crate) use crate::terrain::quadtree::render::*;

/// The central object in terra. It holds all relevant state and provides functions to update and
/// render the terrain.
pub(crate) struct QuadTree {
    // ocean: Ocean<R>,
    /// List of nodes that will be rendered.
    visible_nodes: Vec<VNode>,
    partially_visible_nodes: Vec<(VNode, u8)>,

    heights_resolution: u32,

    node_states: Vec<NodeState>,
}

impl std::fmt::Debug for QuadTree {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "QuadTree")
    }
}

#[allow(unused)]
impl QuadTree {
    pub(crate) fn new(heights_resolution: u32) -> Self {
        Self {
            visible_nodes: Vec::new(),
            partially_visible_nodes: Vec::new(),
            node_states: Vec::new(),
            heights_resolution,
        }
    }

    pub(crate) fn create_index_buffers(
        &self,
        device: &wgpu::Device,
    ) -> (wgpu::Buffer, wgpu::Buffer) {
        let make_index_buffer = |resolution: u16| -> wgpu::Buffer {
            let mapped = device.create_buffer_mapped(
                12 * (resolution as usize + 1) * (resolution as usize + 1),
                wgpu::BufferUsage::INDEX,
            );

            let mut i = 0;
            let width = resolution + 1;
            for y in 0..resolution {
                for x in 0..resolution {
                    for offset in [0, 1, width, 1, width + 1, width].iter() {
                        NativeEndian::write_u16(&mut mapped.data[i..], offset + (x + y * width));
                        i += 2;
                    }
                }
            }

            mapped.finish()
        };
        let resolution = self.heights_resolution as u16;

        (make_index_buffer(resolution), make_index_buffer(resolution / 2))
    }

    pub fn update_cache(&mut self, tile_cache: &mut TileCache, camera: mint::Point3<f32>) {
        let camera = Point3::new(camera.x, camera.y, camera.z);

        tile_cache.update_priorities(camera);

        VNode::breadth_first(|node| {
            let priority = node.priority(camera);
            if priority < Priority::cutoff() {
                return false;
            }

            tile_cache.add_missing((priority, node));

            if node.level() >= 22 {
                return false;
            }

            true
        });
    }

    pub fn update_visibility(
        &mut self,
        tile_cache: &TileCache,
        camera: mint::Point3<f32>,
        cull_frustum: Option<Frustum<f32>>,
    ) {
        let camera = Point3::new(camera.x, camera.y, camera.z);

        self.visible_nodes.clear();
        self.partially_visible_nodes.clear();

        let mut node_visibilities: HashMap<VNode, bool> = HashMap::new();

        // Any node with all needed layers in cache is visible...
        VNode::breadth_first(|node| {
            let visible = node == VNode::root() || node.priority(camera) >= Priority::cutoff();
            node_visibilities.insert(node, visible);
            visible
        });
        let min_missing_level = node_visibilities
            .iter()
            .filter(|(&n, &v)| v && !tile_cache.contains(n, LayerType::Displacements))
            .map(|(n, v)| n.level())
            .min();
        if let Some(min) = min_missing_level {
            for (n, v) in node_visibilities.iter_mut() {
                if n.level() >= min {
                    *v = false;
                }
            }
        }

        // ...Except if all its children are visible instead.
        VNode::breadth_first(|node| {
            if node_visibilities[&node] {
                let mut mask = 0;
                let mut has_visible_children = false;
                for (i, c) in node.children().iter().enumerate() {
                    if !node_visibilities[c] {
                        mask = mask | (1 << i);
                    }

                    if node_visibilities[&c] {
                        has_visible_children = true;
                    }
                }

                if let Some(frustum) = cull_frustum {
                    // TODO: Also try to cull parts of a node, if contains() returns Relation::Cross.
                    if frustum.contains(&node.bounds().as_aabb3()) == Relation::Out {
                        mask = 0;
                    }
                }

                if mask == 0 {
                    node_visibilities.insert(node, false);
                } else if has_visible_children {
                    self.partially_visible_nodes.push((node, mask));
                } else {
                    self.visible_nodes.push(node);
                }

                true
            } else {
                false
            }
        });
    }

    // pub fn get_height(
    //     &self,
    //     mapfile: &MapFile,
    //     tile_cache: &VecMap<TileCache>,
    //     p: Point2<f32>,
    // ) -> Option<f32> {
    //     if self.nodes[0].bounds.min.x > p.x
    //         || self.nodes[0].bounds.max.x < p.x
    //         || self.nodes[0].bounds.min.z > p.y
    //         || self.nodes[0].bounds.max.z < p.y
    //     {
    //         return None;
    //     }

    //     let mut id = NodeId::root();
    //     while self.nodes[id].children.iter().any(|c| c.is_some()) {
    //         for c in self.nodes[id].children.iter() {
    //             if let Some(c) = *c {
    //                 if self.nodes[c].bounds.min.x <= p.x
    //                     && self.nodes[c].bounds.max.x >= p.x
    //                     && self.nodes[c].bounds.min.z <= p.y
    //                     && self.nodes[c].bounds.max.z >= p.y
    //                 {
    //                     id = c;
    //                     break;
    //                 }
    //             }
    //         }
    //     }

    //     let layer = &tile_cache[LayerType::Heights.index()];
    //     let resolution = (layer.resolution() - 1) as f32;
    //     let x = (p.x - self.nodes[id].bounds.min.x) / self.nodes[id].side_length() * resolution;
    //     let y = (p.y - self.nodes[id].bounds.min.z) / self.nodes[id].side_length() * resolution;

    //     let get_texel =
    //         |x, y| layer.get_texel(mapfile, id, x, y).read_f32::<LittleEndian>().unwrap();

    //     let (mut fx, mut fy) = (x.fract(), y.fract());
    //     let (mut ix, mut iy) = (x.floor() as usize, y.floor() as usize);
    //     if ix == layer.resolution() as usize - 1 {
    //         ix = layer.resolution() as usize - 2;
    //         fx = 1.0;
    //     }
    //     if iy == layer.resolution() as usize - 1 {
    //         iy = layer.resolution() as usize - 2;
    //         fy = 1.0;
    //     }

    //     if fx + fy < 1.0 {
    //         Some(
    //             (1.0 - fx - fy) * get_texel(ix, iy)
    //                 + fx * get_texel(ix + 1, iy)
    //                 + fy * get_texel(ix, iy + 1),
    //         )
    //     } else {
    //         Some(
    //             (fx + fy - 1.0) * get_texel(ix + 1, iy + 1)
    //                 + (1.0 - fx) * get_texel(ix, iy + 1)
    //                 + (1.0 - fy) * get_texel(ix + 1, iy),
    //         )
    //     }
    // }
}
<|endoftext|>


<commit_before>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters.
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! A number of these checks can be opted-out of with various directives like
//! `// ignore-tidy-linelength`.

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

const COLS: usize = 100;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(line: &str) -> bool {
    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") => state = EXP_LINK_LABEL_OR_URL,
            (EXP_COMMENT_START, "///") => state = EXP_LINK_LABEL_OR_URL,
            (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:")
                => state = EXP_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.starts_with("http://") || w.starts_with("https://")
                => state = EXP_END,

            (EXP_URL, w)
                if w.starts_with("http://") || w.starts_with("https://") || w.starts_with("../")
                => state = EXP_END,

            (_, _) => return false,
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(line: &str) -> bool {
    if line_is_url(line) {
        return true;
    }

    false
}

pub fn check(path: &Path, bad: &mut bool) {
    let mut contents = String::new();
    super::walk(path, &mut super::filter_dirs, &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
        if extensions.iter().all(|e| !filename.ends_with(e)) ||
           filename.starts_with(".#") {
            return
        }

        contents.truncate(0);
        t!(t!(File::open(file), file).read_to_string(&mut contents));

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let skip_cr = contents.contains("ignore-tidy-cr");
        let skip_tab = contents.contains("ignore-tidy-tab");
        let skip_length = contents.contains("ignore-tidy-linelength");
        let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace");
        let skip_copyright = contents.contains("ignore-tidy-copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if !skip_length && line.chars().count() > COLS
                && !long_line_is_ok(line) {
                    err(&format!("line longer than {} chars", COLS));
            }
            if !skip_tab && line.contains('\t') {
                err("tab character");
            }
            if !skip_end_whitespace && (line.ends_with(' ') || line.ends_with('\t')) {
                err("trailing whitespace");
            }
            if !skip_cr && line.contains('\r') {
                err("CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            if !skip_copyright && (line.starts_with("// Copyright") ||
                                   line.starts_with("# Copyright") ||
                                   line.starts_with("Copyright"))
                               && (line.contains("Rust Developers") ||
                                   line.contains("Rust Project Developers")) {
                err("copyright notices attributed to the Rust Project Developers are deprecated");
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        match trailing_new_lines {
            0 => tidy_error!(bad, "{}: missing trailing newline", file.display()),
            1 => {}
            n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n),
        };
    })
}
<commit_msg>Look specifically for comments containing tidy ignore directives<commit_after>//! Tidy check to enforce various stylistic guidelines on the Rust codebase.
//!
//! Example checks are:
//!
//! * No lines over 100 characters.
//! * No tabs.
//! * No trailing whitespace.
//! * No CR characters.
//! * No `TODO` or `XXX` directives.
//! * No unexplained ` ```ignore ` or ` ```rust,ignore ` doc tests.
//!
//! A number of these checks can be opted-out of with various directives like
//! `// ignore-tidy-linelength`.

use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

const COLS: usize = 100;

const UNEXPLAINED_IGNORE_DOCTEST_INFO: &str = r#"unexplained "```ignore" doctest; try one:

* make the test actually pass, by adding necessary imports and declarations, or
* use "```text", if the code is not Rust code, or
* use "```compile_fail,Ennnn", if the code is expected to fail at compile time, or
* use "```should_panic", if the code is expected to fail at run time, or
* use "```no_run", if the code should type-check but not necessary linkable/runnable, or
* explain it like "```ignore (cannot-test-this-because-xxxx)", if the annotation cannot be avoided.

"#;

const LLVM_UNREACHABLE_INFO: &str = r"\
C++ code used llvm_unreachable, which triggers undefined behavior
when executed when assertions are disabled.
Use llvm::report_fatal_error for increased robustness.";

/// Parser states for `line_is_url`.
#[derive(PartialEq)]
#[allow(non_camel_case_types)]
enum LIUState {
    EXP_COMMENT_START,
    EXP_LINK_LABEL_OR_URL,
    EXP_URL,
    EXP_END,
}

/// Returns `true` if `line` appears to be a line comment containing an URL,
/// possibly with a Markdown link label in front, and nothing else.
/// The Markdown link label, if present, may not contain whitespace.
/// Lines of this form are allowed to be overlength, because Markdown
/// offers no way to split a line in the middle of a URL, and the lengths
/// of URLs to external references are beyond our control.
fn line_is_url(line: &str) -> bool {
    use self::LIUState::*;
    let mut state: LIUState = EXP_COMMENT_START;

    for tok in line.split_whitespace() {
        match (state, tok) {
            (EXP_COMMENT_START, "//") => state = EXP_LINK_LABEL_OR_URL,
            (EXP_COMMENT_START, "///") => state = EXP_LINK_LABEL_OR_URL,
            (EXP_COMMENT_START, "//!") => state = EXP_LINK_LABEL_OR_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.len() >= 4 && w.starts_with('[') && w.ends_with("]:")
                => state = EXP_URL,

            (EXP_LINK_LABEL_OR_URL, w)
                if w.starts_with("http://") || w.starts_with("https://")
                => state = EXP_END,

            (EXP_URL, w)
                if w.starts_with("http://") || w.starts_with("https://") || w.starts_with("../")
                => state = EXP_END,

            (_, _) => return false,
        }
    }

    state == EXP_END
}

/// Returns `true` if `line` is allowed to be longer than the normal limit.
/// Currently there is only one exception, for long URLs, but more
/// may be added in the future.
fn long_line_is_ok(line: &str) -> bool {
    if line_is_url(line) {
        return true;
    }

    false
}

fn contains_ignore_directive(contents: &String, check: &str) -> bool {
    contents.contains(&format!("// ignore-tidy-{}", check)) ||
        contents.contains(&format!("# ignore-tidy-{}", check))
}

pub fn check(path: &Path, bad: &mut bool) {
    let mut contents = String::new();
    super::walk(path, &mut super::filter_dirs, &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h"];
        if extensions.iter().all(|e| !filename.ends_with(e)) ||
           filename.starts_with(".#") {
            return
        }

        contents.truncate(0);
        t!(t!(File::open(file), file).read_to_string(&mut contents));

        if contents.is_empty() {
            tidy_error!(bad, "{}: empty file", file.display());
        }

        let skip_cr = contains_ignore_directive(&contents, "cr");
        let skip_tab = contains_ignore_directive(&contents, "tab");
        let skip_length = contains_ignore_directive(&contents, "linelength");
        let skip_end_whitespace = contains_ignore_directive(&contents, "end-whitespace");
        let skip_copyright = contains_ignore_directive(&contents, "copyright");
        let mut leading_new_lines = false;
        let mut trailing_new_lines = 0;
        for (i, line) in contents.split('\n').enumerate() {
            let mut err = |msg: &str| {
                tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg);
            };
            if !skip_length && line.chars().count() > COLS
                && !long_line_is_ok(line) {
                    err(&format!("line longer than {} chars", COLS));
            }
            if !skip_tab && line.contains('\t') {
                err("tab character");
            }
            if !skip_end_whitespace && (line.ends_with(' ') || line.ends_with('\t')) {
                err("trailing whitespace");
            }
            if !skip_cr && line.contains('\r') {
                err("CR character");
            }
            if filename != "style.rs" {
                if line.contains("TODO") {
                    err("TODO is deprecated; use FIXME")
                }
                if line.contains("//") && line.contains(" XXX") {
                    err("XXX is deprecated; use FIXME")
                }
            }
            if !skip_copyright && (line.starts_with("// Copyright") ||
                                   line.starts_with("# Copyright") ||
                                   line.starts_with("Copyright"))
                               && (line.contains("Rust Developers") ||
                                   line.contains("Rust Project Developers")) {
                err("copyright notices attributed to the Rust Project Developers are deprecated");
            }
            if line.ends_with("```ignore") || line.ends_with("```rust,ignore") {
                err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
            }
            if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
                err(LLVM_UNREACHABLE_INFO);
            }
            if line.is_empty() {
                if i == 0 {
                    leading_new_lines = true;
                }
                trailing_new_lines += 1;
            } else {
                trailing_new_lines = 0;
            }
        }
        if leading_new_lines {
            tidy_error!(bad, "{}: leading newline", file.display());
        }
        match trailing_new_lines {
            0 => tidy_error!(bad, "{}: missing trailing newline", file.display()),
            1 => {}
            n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n),
        };
    })
}
<|endoftext|>