<commit_before>use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::ReflectValueBox;
use protobuf::Message;
use protobuf::ProtobufEnum;

use super::test_reflect_pb::*;
use protobuf::reflect::RuntimeFieldType;

use protobuf_test_common::value_for_runtime_type;

#[test]
fn test_get_sub_message_via_reflection() {
    let mut m = M::new();
    m.mut_sub_m().set_n(42);
    assert!(m.has_sub_m());

    let descriptor = m.descriptor().field_by_name("sub_m").unwrap();
    assert_eq!("sub_m", descriptor.name());

    let sub_m = descriptor.get_message(&m);
    assert_eq!("test_reflect.SubM", sub_m.descriptor().full_name());
    assert_eq!(
        42,
        sub_m
            .descriptor()
            .field_by_name("n")
            .unwrap()
            .get_i32(sub_m)
    );
}

#[test]
fn test_singular_basic() {
    let mut message = TestTypesSingular::new();
    let descriptor = message.descriptor();

    let bool_field = descriptor.field_by_name("bool_field").unwrap();
    assert!(!bool_field.has_field(&message));

    bool_field.set_singular_field(&mut message, ReflectValueBox::Bool(true));
    assert!(bool_field.has_field(&message));
    assert_eq!(true, bool_field.get_bool(&message));
}

fn test_singular_field(message: &mut Message, field: &FieldDescriptor) {
    assert!(!field.has_field(message));

    // should not crash
    field.get_singular_field_or_default(message);

    let value = value_for_runtime_type(field.singular_runtime_type());
    field.set_singular_field(message, value);
}

#[test]
fn test_singular() {
    let mut message = TestTypesSingular::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_singular_field(&mut message, field);
    }
}

#[test]
fn test_repeated_debug() {
    let mut message = TestTypesRepeated::new();
    message.set_int32_field(vec![10, 20, 30]);
    let field = message
        .descriptor()
        .field_by_name("int32_field")
        .unwrap()
        .get_repeated(&message);
    assert_eq!("[10, 20, 30]", format!("{:?}", field));
}

fn test_repeated_field(message: &mut Message, field: &FieldDescriptor) {
    assert_eq!(0, field.len_field(message));
    assert!(!field.has_field(message));

    let mut expected = Vec::new();

    // test mut interface
    {
        let mut repeated = field.mut_repeated(message);

        for i in 0..3 {
            let value = value_for_runtime_type(repeated.element_type());
            expected.push(value.clone());
            repeated.push(value.clone());
            let fetched = repeated.get(i);
            assert_eq!(value, fetched);
        }

        assert_eq!(expected, repeated);
        assert_eq!(repeated, expected);
    }

    // test read interface
    {
        let repeated = field.get_repeated(message);
        assert_eq!(3, repeated.len());

        assert_eq!(expected, repeated);
        assert_eq!(repeated, expected);
    }
}

#[test]
fn test_repeated() {
    let mut message = TestTypesRepeated::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_repeated_field(&mut message, field);
    }
}

fn test_map_field(message: &mut Message, field: &FieldDescriptor) {
    assert!(field.get_map(message).is_empty());
    assert_eq!(0, field.get_map(message).len());
    assert!(field.mut_map(message).is_empty());
    assert_eq!(0, field.mut_map(message).len());

    let (k, v) = match field.runtime_field_type() {
        RuntimeFieldType::Map(k, v) => (k, v),
        _ => panic!("not a map"),
    };

    {
        let map = field.get_map(message);
        assert!(map.is_empty());
        assert_eq!(0, map.len());

        assert_eq!(None, map.get(value_for_runtime_type(k).as_value_ref()));
    }

    {
        let mut map = field.mut_map(message);
        assert!(map.is_empty());
        assert_eq!(0, map.len());

        assert_eq!(None, map.get(value_for_runtime_type(k).as_value_ref()));

        let key = value_for_runtime_type(k);
        let value = value_for_runtime_type(v);

        map.insert(key.clone(), value.clone());

        assert_eq!(Some(value.as_value_ref()), map.get(key.as_value_ref()));

        assert_eq!(1, map.len());
    }
}

#[test]
fn test_map() {
    let mut message = TestTypesMap::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_map_field(&mut message, field);
    }
}

#[test]
fn test_nested_message() {
    assert_eq!("test_reflect.WithNestedMessage.NestedMessage",
        with_nested_message::NestedMessage::descriptor_static().full_name());
}

#[test]
fn test_nested_enum() {
    assert_eq!("test_reflect.WithNestedMessage.NestedEnum",
        with_nested_message::NestedEnum::enum_descriptor_static().full_name());
}

#[test]
fn test_mut_message() {
    let mut m = TestTypesSingular::new();
    {
        let message_field_field = m.descriptor().field_by_name("message_field").unwrap();
        let sub_m = message_field_field.mut_message(&mut m);
        let n_field = sub_m.descriptor().field_by_name("n").unwrap();
        n_field.set_singular_field(sub_m, ReflectValueBox::I32(10));
        // TODO: test `mut_message` works for oneof fields
    }
    assert_eq!(10, m.get_message_field().get_n());
}
<commit_msg>Missing dyn before trait in tests<commit_after>use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::ReflectValueBox;
use protobuf::Message;
use protobuf::ProtobufEnum;

use super::test_reflect_pb::*;
use protobuf::reflect::RuntimeFieldType;

use protobuf_test_common::value_for_runtime_type;

#[test]
fn test_get_sub_message_via_reflection() {
    let mut m = M::new();
    m.mut_sub_m().set_n(42);
    assert!(m.has_sub_m());

    let descriptor = m.descriptor().field_by_name("sub_m").unwrap();
    assert_eq!("sub_m", descriptor.name());

    let sub_m = descriptor.get_message(&m);
    assert_eq!("test_reflect.SubM", sub_m.descriptor().full_name());
    assert_eq!(
        42,
        sub_m
            .descriptor()
            .field_by_name("n")
            .unwrap()
            .get_i32(sub_m)
    );
}

#[test]
fn test_singular_basic() {
    let mut message = TestTypesSingular::new();
    let descriptor = message.descriptor();

    let bool_field = descriptor.field_by_name("bool_field").unwrap();
    assert!(!bool_field.has_field(&message));

    bool_field.set_singular_field(&mut message, ReflectValueBox::Bool(true));
    assert!(bool_field.has_field(&message));
    assert_eq!(true, bool_field.get_bool(&message));
}

fn test_singular_field(message: &mut dyn Message, field: &FieldDescriptor) {
    assert!(!field.has_field(message));

    // should not crash
    field.get_singular_field_or_default(message);

    let value = value_for_runtime_type(field.singular_runtime_type());
    field.set_singular_field(message, value);
}

#[test]
fn test_singular() {
    let mut message = TestTypesSingular::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_singular_field(&mut message, field);
    }
}

#[test]
fn test_repeated_debug() {
    let mut message = TestTypesRepeated::new();
    message.set_int32_field(vec![10, 20, 30]);
    let field = message
        .descriptor()
        .field_by_name("int32_field")
        .unwrap()
        .get_repeated(&message);
    assert_eq!("[10, 20, 30]", format!("{:?}", field));
}

fn test_repeated_field(message: &mut dyn Message, field: &FieldDescriptor) {
    assert_eq!(0, field.len_field(message));
    assert!(!field.has_field(message));

    let mut expected = Vec::new();

    // test mut interface
    {
        let mut repeated = field.mut_repeated(message);

        for i in 0..3 {
            let value = value_for_runtime_type(repeated.element_type());
            expected.push(value.clone());
            repeated.push(value.clone());
            let fetched = repeated.get(i);
            assert_eq!(value, fetched);
        }

        assert_eq!(expected, repeated);
        assert_eq!(repeated, expected);
    }

    // test read interface
    {
        let repeated = field.get_repeated(message);
        assert_eq!(3, repeated.len());

        assert_eq!(expected, repeated);
        assert_eq!(repeated, expected);
    }
}

#[test]
fn test_repeated() {
    let mut message = TestTypesRepeated::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_repeated_field(&mut message, field);
    }
}

fn test_map_field(message: &mut dyn Message, field: &FieldDescriptor) {
    assert!(field.get_map(message).is_empty());
    assert_eq!(0, field.get_map(message).len());
    assert!(field.mut_map(message).is_empty());
    assert_eq!(0, field.mut_map(message).len());

    let (k, v) = match field.runtime_field_type() {
        RuntimeFieldType::Map(k, v) => (k, v),
        _ => panic!("not a map"),
    };

    {
        let map = field.get_map(message);
        assert!(map.is_empty());
        assert_eq!(0, map.len());

        assert_eq!(None, map.get(value_for_runtime_type(k).as_value_ref()));
    }

    {
        let mut map = field.mut_map(message);
        assert!(map.is_empty());
        assert_eq!(0, map.len());

        assert_eq!(None, map.get(value_for_runtime_type(k).as_value_ref()));

        let key = value_for_runtime_type(k);
        let value = value_for_runtime_type(v);

        map.insert(key.clone(), value.clone());

        assert_eq!(Some(value.as_value_ref()), map.get(key.as_value_ref()));

        assert_eq!(1, map.len());
    }
}

#[test]
fn test_map() {
    let mut message = TestTypesMap::new();
    let descriptor = message.descriptor();

    for field in descriptor.fields() {
        test_map_field(&mut message, field);
    }
}

#[test]
fn test_nested_message() {
    assert_eq!("test_reflect.WithNestedMessage.NestedMessage",
        with_nested_message::NestedMessage::descriptor_static().full_name());
}

#[test]
fn test_nested_enum() {
    assert_eq!("test_reflect.WithNestedMessage.NestedEnum",
        with_nested_message::NestedEnum::enum_descriptor_static().full_name());
}

#[test]
fn test_mut_message() {
    let mut m = TestTypesSingular::new();
    {
        let message_field_field = m.descriptor().field_by_name("message_field").unwrap();
        let sub_m = message_field_field.mut_message(&mut m);
        let n_field = sub_m.descriptor().field_by_name("n").unwrap();
        n_field.set_singular_field(sub_m, ReflectValueBox::I32(10));
        // TODO: test `mut_message` works for oneof fields
    }
    assert_eq!(10, m.get_message_field().get_n());
}
<|endoftext|>


<commit_before>extern crate libsqlite3_sys as ffi;

use super::raw::RawConnection;
use super::row::PrivateSqliteRow;
use super::serialized_value::SerializedValue;
use super::{Sqlite, SqliteAggregateFunction};
use crate::deserialize::{FromSqlRow, StaticallySizedRow};
use crate::result::{DatabaseErrorKind, Error, QueryResult};
use crate::row::{Field, PartialRow, Row, RowGatWorkaround, RowIndex};
use crate::serialize::{IsNull, Output, ToSql};
use crate::sql_types::HasSqlType;
use crate::sqlite::connection::sqlite_value::OwnedSqliteValue;
use crate::sqlite::SqliteValue;
use std::cell::{Ref, RefCell};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::DerefMut;
use std::rc::Rc;

pub fn register<ArgsSqlType, RetSqlType, Args, Ret, F>(
    conn: &RawConnection,
    fn_name: &str,
    deterministic: bool,
    mut f: F,
) -> QueryResult<()>
where
    F: FnMut(&RawConnection, Args) -> Ret + std::panic::UnwindSafe + Send + 'static,
    Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let fields_needed = Args::FIELD_COUNT;
    if fields_needed > 127 {
        return Err(Error::DatabaseError(
            DatabaseErrorKind::UnableToSendCommand,
            Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
        ));
    }

    conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| {
        let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;

        let result = f(conn, args);

        process_sql_function_result::<RetSqlType, Ret>(result)
    })?;
    Ok(())
}

pub fn register_noargs<RetSqlType, Ret, F>(
    conn: &RawConnection,
    fn_name: &str,
    deterministic: bool,
    mut f: F,
) -> QueryResult<()>
where
    F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    conn.register_sql_function(fn_name, 0, deterministic, move |_, _| {
        let result = f();
        process_sql_function_result::<RetSqlType, Ret>(result)
    })?;
    Ok(())
}

pub fn register_aggregate<ArgsSqlType, RetSqlType, Args, Ret, A>(
    conn: &RawConnection,
    fn_name: &str,
) -> QueryResult<()>
where
    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + std::panic::UnwindSafe,
    Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let fields_needed = Args::FIELD_COUNT;
    if fields_needed > 127 {
        return Err(Error::DatabaseError(
            DatabaseErrorKind::UnableToSendCommand,
            Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
        ));
    }

    conn.register_aggregate_function::<ArgsSqlType, RetSqlType, Args, Ret, A>(
        fn_name,
        fields_needed,
    )?;

    Ok(())
}

pub(crate) fn build_sql_function_args<ArgsSqlType, Args>(
    args: &mut [*mut ffi::sqlite3_value],
) -> Result<Args, Error>
where
    Args: FromSqlRow<ArgsSqlType, Sqlite>,
{
    let row = FunctionRow::new(args);
    Args::build_from_row(&row).map_err(Error::DeserializationError)
}

pub(crate) fn process_sql_function_result<RetSqlType, Ret>(
    result: Ret,
) -> QueryResult<SerializedValue>
where
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let mut metadata_lookup = ();
    let mut buf = Output::new(Vec::new(), &mut metadata_lookup);
    let is_null = result.to_sql(&mut buf).map_err(Error::SerializationError)?;

    let bytes = if let IsNull::Yes = is_null {
        None
    } else {
        Some(buf.into_inner())
    };

    Ok(SerializedValue {
        ty: Sqlite::metadata(&mut ()),
        data: bytes,
    })
}

struct FunctionRow<'a> {
    // we use `ManuallyDrop` to prevent dropping the content of the internal vector
    // as this buffer is owned by sqlite not by diesel
    args: Rc<RefCell<ManuallyDrop<PrivateSqliteRow<'a>>>>,
    field_count: usize,
    marker: PhantomData<&'a ffi::sqlite3_value>,
}

impl<'a> Drop for FunctionRow<'a> {
    fn drop(&mut self) {
        if let Some(args) = Rc::get_mut(&mut self.args) {
            if let PrivateSqliteRow::Duplicated { column_names, .. } =
                DerefMut::deref_mut(RefCell::get_mut(args))
            {
                if let Some(inner) = Rc::get_mut(column_names) {
                    // According the https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html#method.drop
                    // it's fine to just drop the values here
                    unsafe { std::ptr::drop_in_place(inner as *mut _) }
                }
            }
        }
    }
}

impl<'a> FunctionRow<'a> {
    fn new(args: &mut [*mut ffi::sqlite3_value]) -> Self {
        let lenghts = args.len();
        let args = unsafe {
            Vec::from_raw_parts(
                // This cast is safe because:
                // * Casting from a pointer to an arry to a pointer to the first array
                // element is safe
                // * Casting from a raw pointer to `NonNull<T>` is safe,
                // because `NonNull` is #[repr(transparent)]
                // * Casting from `NonNull<T>` to `OwnedSqliteValue` is safe,
                // as the struct is `#[repr(transparent)]
                // * Casting from `NonNull<T>` to `Option<NonNull<T>>` as the documentation
                // states: "This is so that enums may use this forbidden value as a discriminant –
                // Option<NonNull<T>> has the same size as *mut T"
                // * The last point remains true for `OwnedSqliteValue` as `#[repr(transparent)]
                // guarantees the same layout as the inner type
                // * It's unsafe to drop the vector (and the vector elements)
                // because of this we wrap the vector (or better the Row)
                // Into `ManualDrop` to prevent the dropping
                args as *mut [*mut ffi::sqlite3_value] as *mut ffi::sqlite3_value
                    as *mut Option<OwnedSqliteValue>,
                lenghts,
                lenghts,
            )
        };

        Self {
            field_count: lenghts,
            args: Rc::new(RefCell::new(ManuallyDrop::new(
                PrivateSqliteRow::Duplicated {
                    values: args,
                    column_names: Rc::from(vec![None; lenghts]),
                },
            ))),
            marker: PhantomData,
        }
    }
}

impl<'a, 'b> RowGatWorkaround<'a, Sqlite> for FunctionRow<'b> {
    type Field = FunctionArgument<'a>;
}

impl<'a> Row<'a, Sqlite> for FunctionRow<'a> {
    type InnerPartialRow = Self;

    fn field_count(&self) -> usize {
        self.field_count
    }

    fn get<'b, I>(&'b self, idx: I) -> Option<<Self as RowGatWorkaround<'b, Sqlite>>::Field>
    where
        'a: 'b,
        Self: crate::row::RowIndex<I>,
    {
        let idx = self.idx(idx)?;
        Some(FunctionArgument {
            args: self.args.borrow(),
            col_idx: idx as i32,
        })
    }

    fn partial_row(&self, range: std::ops::Range<usize>) -> PartialRow<Self::InnerPartialRow> {
        PartialRow::new(self, range)
    }
}

impl<'a> RowIndex<usize> for FunctionRow<'a> {
    fn idx(&self, idx: usize) -> Option<usize> {
        if idx < self.field_count() {
            Some(idx)
        } else {
            None
        }
    }
}

impl<'a, 'b> RowIndex<&'a str> for FunctionRow<'b> {
    fn idx(&self, _idx: &'a str) -> Option<usize> {
        None
    }
}

struct FunctionArgument<'a> {
    args: Ref<'a, ManuallyDrop<PrivateSqliteRow<'a>>>,
    col_idx: i32,
}

impl<'a> Field<'a, Sqlite> for FunctionArgument<'a> {
    fn field_name(&self) -> Option<&str> {
        None
    }

    fn is_null(&self) -> bool {
        self.value().is_none()
    }

    fn value(&self) -> Option<crate::backend::RawValue<Sqlite>> {
        SqliteValue::new(
            Ref::map(Ref::clone(&self.args), |drop| std::ops::Deref::deref(drop)),
            self.col_idx,
        )
    }
}
<commit_msg>Apply suggestions from code review<commit_after>extern crate libsqlite3_sys as ffi;

use super::raw::RawConnection;
use super::row::PrivateSqliteRow;
use super::serialized_value::SerializedValue;
use super::{Sqlite, SqliteAggregateFunction};
use crate::deserialize::{FromSqlRow, StaticallySizedRow};
use crate::result::{DatabaseErrorKind, Error, QueryResult};
use crate::row::{Field, PartialRow, Row, RowGatWorkaround, RowIndex};
use crate::serialize::{IsNull, Output, ToSql};
use crate::sql_types::HasSqlType;
use crate::sqlite::connection::sqlite_value::OwnedSqliteValue;
use crate::sqlite::SqliteValue;
use std::cell::{Ref, RefCell};
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ops::DerefMut;
use std::rc::Rc;

pub fn register<ArgsSqlType, RetSqlType, Args, Ret, F>(
    conn: &RawConnection,
    fn_name: &str,
    deterministic: bool,
    mut f: F,
) -> QueryResult<()>
where
    F: FnMut(&RawConnection, Args) -> Ret + std::panic::UnwindSafe + Send + 'static,
    Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let fields_needed = Args::FIELD_COUNT;
    if fields_needed > 127 {
        return Err(Error::DatabaseError(
            DatabaseErrorKind::UnableToSendCommand,
            Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
        ));
    }

    conn.register_sql_function(fn_name, fields_needed, deterministic, move |conn, args| {
        let args = build_sql_function_args::<ArgsSqlType, Args>(args)?;

        let result = f(conn, args);

        process_sql_function_result::<RetSqlType, Ret>(result)
    })?;
    Ok(())
}

pub fn register_noargs<RetSqlType, Ret, F>(
    conn: &RawConnection,
    fn_name: &str,
    deterministic: bool,
    mut f: F,
) -> QueryResult<()>
where
    F: FnMut() -> Ret + std::panic::UnwindSafe + Send + 'static,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    conn.register_sql_function(fn_name, 0, deterministic, move |_, _| {
        let result = f();
        process_sql_function_result::<RetSqlType, Ret>(result)
    })?;
    Ok(())
}

pub fn register_aggregate<ArgsSqlType, RetSqlType, Args, Ret, A>(
    conn: &RawConnection,
    fn_name: &str,
) -> QueryResult<()>
where
    A: SqliteAggregateFunction<Args, Output = Ret> + 'static + Send + std::panic::UnwindSafe,
    Args: FromSqlRow<ArgsSqlType, Sqlite> + StaticallySizedRow<ArgsSqlType, Sqlite>,
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let fields_needed = Args::FIELD_COUNT;
    if fields_needed > 127 {
        return Err(Error::DatabaseError(
            DatabaseErrorKind::UnableToSendCommand,
            Box::new("SQLite functions cannot take more than 127 parameters".to_string()),
        ));
    }

    conn.register_aggregate_function::<ArgsSqlType, RetSqlType, Args, Ret, A>(
        fn_name,
        fields_needed,
    )?;

    Ok(())
}

pub(crate) fn build_sql_function_args<ArgsSqlType, Args>(
    args: &mut [*mut ffi::sqlite3_value],
) -> Result<Args, Error>
where
    Args: FromSqlRow<ArgsSqlType, Sqlite>,
{
    let row = FunctionRow::new(args);
    Args::build_from_row(&row).map_err(Error::DeserializationError)
}

pub(crate) fn process_sql_function_result<RetSqlType, Ret>(
    result: Ret,
) -> QueryResult<SerializedValue>
where
    Ret: ToSql<RetSqlType, Sqlite>,
    Sqlite: HasSqlType<RetSqlType>,
{
    let mut metadata_lookup = ();
    let mut buf = Output::new(Vec::new(), &mut metadata_lookup);
    let is_null = result.to_sql(&mut buf).map_err(Error::SerializationError)?;

    let bytes = if let IsNull::Yes = is_null {
        None
    } else {
        Some(buf.into_inner())
    };

    Ok(SerializedValue {
        ty: Sqlite::metadata(&mut ()),
        data: bytes,
    })
}

struct FunctionRow<'a> {
    // we use `ManuallyDrop` to prevent dropping the content of the internal vector
    // as this buffer is owned by sqlite not by diesel
    args: Rc<RefCell<ManuallyDrop<PrivateSqliteRow<'a>>>>,
    field_count: usize,
    marker: PhantomData<&'a ffi::sqlite3_value>,
}

impl<'a> Drop for FunctionRow<'a> {
    fn drop(&mut self) {
        if let Some(args) = Rc::get_mut(&mut self.args) {
            if let PrivateSqliteRow::Duplicated { column_names, .. } =
                DerefMut::deref_mut(RefCell::get_mut(args))
            {
                if let Some(inner) = Rc::get_mut(column_names) {
                    // According the https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html#method.drop
                    // it's fine to just drop the values here
                    unsafe { std::ptr::drop_in_place(inner as *mut _) }
                }
            }
        }
    }
}

impl<'a> FunctionRow<'a> {
    fn new(args: &mut [*mut ffi::sqlite3_value]) -> Self {
        let lenghts = args.len();
        let args = unsafe {
            Vec::from_raw_parts(
                // This cast is safe because:
                // * Casting from a pointer to an array to a pointer to the first array
                // element is safe
                // * Casting from a raw pointer to `NonNull<T>` is safe,
                // because `NonNull` is #[repr(transparent)]
                // * Casting from `NonNull<T>` to `OwnedSqliteValue` is safe,
                // as the struct is `#[repr(transparent)]
                // * Casting from `NonNull<T>` to `Option<NonNull<T>>` as the documentation
                // states: "This is so that enums may use this forbidden value as a discriminant –
                // Option<NonNull<T>> has the same size as *mut T"
                // * The last point remains true for `OwnedSqliteValue` as `#[repr(transparent)]
                // guarantees the same layout as the inner type
                // * It's unsafe to drop the vector (and the vector elements)
                // because of this we wrap the vector (or better the Row)
                // Into `ManualDrop` to prevent the dropping
                args as *mut [*mut ffi::sqlite3_value] as *mut ffi::sqlite3_value
                    as *mut Option<OwnedSqliteValue>,
                lenghts,
                lenghts,
            )
        };

        Self {
            field_count: lenghts,
            args: Rc::new(RefCell::new(ManuallyDrop::new(
                PrivateSqliteRow::Duplicated {
                    values: args,
                    column_names: Rc::from(vec![None; lenghts]),
                },
            ))),
            marker: PhantomData,
        }
    }
}

impl<'a, 'b> RowGatWorkaround<'a, Sqlite> for FunctionRow<'b> {
    type Field = FunctionArgument<'a>;
}

impl<'a> Row<'a, Sqlite> for FunctionRow<'a> {
    type InnerPartialRow = Self;

    fn field_count(&self) -> usize {
        self.field_count
    }

    fn get<'b, I>(&'b self, idx: I) -> Option<<Self as RowGatWorkaround<'b, Sqlite>>::Field>
    where
        'a: 'b,
        Self: crate::row::RowIndex<I>,
    {
        let idx = self.idx(idx)?;
        Some(FunctionArgument {
            args: self.args.borrow(),
            col_idx: idx as i32,
        })
    }

    fn partial_row(&self, range: std::ops::Range<usize>) -> PartialRow<Self::InnerPartialRow> {
        PartialRow::new(self, range)
    }
}

impl<'a> RowIndex<usize> for FunctionRow<'a> {
    fn idx(&self, idx: usize) -> Option<usize> {
        if idx < self.field_count() {
            Some(idx)
        } else {
            None
        }
    }
}

impl<'a, 'b> RowIndex<&'a str> for FunctionRow<'b> {
    fn idx(&self, _idx: &'a str) -> Option<usize> {
        None
    }
}

struct FunctionArgument<'a> {
    args: Ref<'a, ManuallyDrop<PrivateSqliteRow<'a>>>,
    col_idx: i32,
}

impl<'a> Field<'a, Sqlite> for FunctionArgument<'a> {
    fn field_name(&self) -> Option<&str> {
        None
    }

    fn is_null(&self) -> bool {
        self.value().is_none()
    }

    fn value(&self) -> Option<crate::backend::RawValue<Sqlite>> {
        SqliteValue::new(
            Ref::map(Ref::clone(&self.args), |drop| std::ops::Deref::deref(drop)),
            self.col_idx,
        )
    }
}
<|endoftext|>


<commit_before>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLResourceOptions, MTLSize};

/// The `MTLDevice` protocol defines the interface to a single graphics processor (GPU). You use
/// an object that conforms to this protocol to query the capabilities of the processor and to
/// allocate objects used to access those capabilities.
///
/// Your app does not define classes that implement this protocol; it is used by Metal to provide
/// a device object to your app. To obtain a system device, call the `MTLCreateSystemDefaultDevice`
/// function or select a result from the `MTLCopyAllDevices` function.
///
/// Most objects in Metal that perform graphics rendering and computational work are associated
/// directly with a specific device. For example, texture objects are created by a device object
/// and can be used only with that device. Most methods on a `MTLDevice` object create non-transient
/// objects, including command queues, resources (such as buffers and textures), and pipeline
/// states. These objects can be expensive to create and you are encouraged to create them soon
/// after your app launches and reuse them throughout the lifetime of your app. Avoid creating these
/// objects in performance sensitive code.
pub trait MTLDevice {
    /// A Boolean value that indicates whether a device supports a packed depth/stencil buffer.
    /// (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device supports the `MTLPixelFormatDepth24Unorm_Stencil8` pixel
    /// format.
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;

    /// A Boolean value that indicates whether a device is configured as headless. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device can not and does not have any displays attached.
    unsafe fn headless(self) -> BOOL;

    /// Boolean value that indicates whether a device is low-power. (read-only)
    ///
    /// # Discussion
    ///
    /// On multi-GPU systems that support automatic graphics switching, this property will return
    /// `YES` for the lower-power GPU.
    unsafe fn lowPower(self) -> BOOL;

    /// The maximum number of threads along each dimension of a threadgroup. (read-only)
    ///
    /// # Discussion
    ///
    /// This is the maximum compute grid size (width, height, depth) supported by the device.
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;

    /// A string that identifies the device. (read-only)
    ///
    /// # Discussion
    ///
    /// When this object is viewed in the Xcode debugger, its name is used to label the device.
    /// The name should only be used for informational purposes.
    unsafe fn name(self) -> id;

    /// Determines whether a device implements a particular feature set.
    ///
    /// # Parameters
    ///
    /// `featureSet` - A value that indicates the feature set you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the feature set is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;

    /// Determines whether a device supports a given texture sample count.
    ///
    /// # Parameters
    ///
    /// `textureSampleCount` - The sample count you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the sample count is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id;
    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id;

    unsafe fn newCommandQueue(self) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id;

    unsafe fn newBufferWithLength_options(self, length: NSUInteger, options: MTLResourceOptions) -> id;
    // TODO(burtonage): Check mutability here
    unsafe fn newBufferWithBytes_length_options(self, pointer: *const c_void, length: NSUInteger,
                                                options: MTLResourceOptions)
                                                -> id;
    // TODO(burtonage): Check mutability here
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  options: MTLResourceOptions,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id, completionHandler: MTLNewRenderPipleineStateCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
            self, function: id, completionHandler: MTLNewComputePipelineStateCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

    unsafe fn name(self) -> id {
        msg_send![self, name]
    }

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

    unsafe fn newDefaultLibrary(self) -> id {
        msg_send![self, newDefaultLibrary]
    }

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler)
        -> id {
        msg_send![self, newLibraryWithSource:source options:options
                           completionHandler:completionHandler]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithData:data error:error]
    }

    unsafe fn newCommandQueue(self) -> id {
        msg_send![self, newCommandQueue]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_options(self, length: NSUInteger, options: MTLResourceOptions) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_length_options(self, pointer: *const c_void, length: NSUInteger,
                                                options: MTLResourceOptions)
                                                -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  options: MTLResourceOptions,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer
                                          length:length
                                         options:options
                                     deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id,
            completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                                 reflection:reflection
                                                      error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}

pub type MTLNewLibraryCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
<commit_msg>Remove todo comments ; it's correct<commit_after>#![allow(unused_variables)]

use block::Block;
use cocoa::base::{BOOL, id};
use cocoa::foundation::NSUInteger;
use libc::c_void;
use {MTLFeatureSet, MTLPipelineOption, MTLResourceOptions, MTLSize};

/// The `MTLDevice` protocol defines the interface to a single graphics processor (GPU). You use
/// an object that conforms to this protocol to query the capabilities of the processor and to
/// allocate objects used to access those capabilities.
///
/// Your app does not define classes that implement this protocol; it is used by Metal to provide
/// a device object to your app. To obtain a system device, call the `MTLCreateSystemDefaultDevice`
/// function or select a result from the `MTLCopyAllDevices` function.
///
/// Most objects in Metal that perform graphics rendering and computational work are associated
/// directly with a specific device. For example, texture objects are created by a device object
/// and can be used only with that device. Most methods on a `MTLDevice` object create non-transient
/// objects, including command queues, resources (such as buffers and textures), and pipeline
/// states. These objects can be expensive to create and you are encouraged to create them soon
/// after your app launches and reuse them throughout the lifetime of your app. Avoid creating these
/// objects in performance sensitive code.
pub trait MTLDevice {
    /// A Boolean value that indicates whether a device supports a packed depth/stencil buffer.
    /// (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device supports the `MTLPixelFormatDepth24Unorm_Stencil8` pixel
    /// format.
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL;

    /// A Boolean value that indicates whether a device is configured as headless. (read-only)
    ///
    /// # Discussion
    ///
    /// If the value is `YES`, the device can not and does not have any displays attached.
    unsafe fn headless(self) -> BOOL;

    /// Boolean value that indicates whether a device is low-power. (read-only)
    ///
    /// # Discussion
    ///
    /// On multi-GPU systems that support automatic graphics switching, this property will return
    /// `YES` for the lower-power GPU.
    unsafe fn lowPower(self) -> BOOL;

    /// The maximum number of threads along each dimension of a threadgroup. (read-only)
    ///
    /// # Discussion
    ///
    /// This is the maximum compute grid size (width, height, depth) supported by the device.
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn maxThreadsPerGroup(self) -> MTLSize;

    /// A string that identifies the device. (read-only)
    ///
    /// # Discussion
    ///
    /// When this object is viewed in the Xcode debugger, its name is used to label the device.
    /// The name should only be used for informational purposes.
    unsafe fn name(self) -> id;

    /// Determines whether a device implements a particular feature set.
    ///
    /// # Parameters
    ///
    /// `featureSet` - A value that indicates the feature set you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the feature set is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL;

    /// Determines whether a device supports a given texture sample count.
    ///
    /// # Parameters
    ///
    /// `textureSampleCount` - The sample count you are interested in.
    ///
    /// # Return Value
    ///
    /// `YES` if the sample count is supported by the device; otherwise `NO`.
    ///
    /// # Discussion
    ///
    /// For more information on the specific capabilities of each feature set, see
    /// [Metal Programming Guide](https://developer.apple.com/library/prerelease/ios/documentation/
    ///     Miscellaneous/Conceptual/MetalProgrammingGuide/Introduction/
    ///     Introduction.html#//apple_ref/doc/uid/TP40014221
    /// ).
    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL;

    unsafe fn newDefaultLibrary(self) -> id;
    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id;
    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id;
    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id;

    unsafe fn newCommandQueue(self) -> id;

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id;

    unsafe fn newBufferWithLength_options(self, length: NSUInteger, options: MTLResourceOptions) -> id;
    unsafe fn newBufferWithBytes_length_options(self, pointer: *const c_void, length: NSUInteger,
                                                options: MTLResourceOptions)
                                                -> id;
    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  options: MTLResourceOptions,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>);

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id;

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id, completionHandler: MTLNewRenderPipleineStateCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler);

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id);

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
            self, function: id, completionHandler: MTLNewComputePipelineStateCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id);

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id);

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler);

    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id);
}

impl MTLDevice for id {
    unsafe fn depth24Stencil8PixelFormatSupported(self) -> BOOL {
        msg_send![self, isDepth24Stencil8PixelFormatSupported]
    }

    unsafe fn headless(self) -> BOOL {
        msg_send![self, isHeadless]
    }

    unsafe fn lowPower(self) -> BOOL {
        msg_send![self, isLowPower]
    }

    unsafe fn maxThreadsPerGroup(self) -> MTLSize {
        msg_send![self, maxThreadsPerThreadgroup]
    }

    unsafe fn name(self) -> id {
        msg_send![self, name]
    }

    unsafe fn supportsFeatureSet(self, featureSet: MTLFeatureSet) -> BOOL {
        msg_send![self, supportsFeatureSet:featureSet]
    }

    unsafe fn supportsTextureSampleCount(self, textureSampleCount: NSUInteger) -> BOOL {
        msg_send![self, supportsTextureSampleCount:textureSampleCount]
    }

    unsafe fn newDefaultLibrary(self) -> id {
        msg_send![self, newDefaultLibrary]
    }

    unsafe fn newLibraryWithFile_error(self, filePath: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithFile:filePath error:error]
    }

    unsafe fn newLibraryWithSource_options_completionHandler(
        self, source: id, options: id, completionHandler: MTLNewLibraryCompletionHandler)
        -> id {
        msg_send![self, newLibraryWithSource:source options:options
                           completionHandler:completionHandler]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newLibraryWithSource_options_error(self, source: id, options: id, error: *mut id)
                                                 -> id {
        msg_send![self, newLibraryWithSource:source options:options error:error]
    }

    unsafe fn newLibraryWithData_error(self, data: id, error: *mut id) -> id {
        msg_send![self, newLibraryWithData:data error:error]
    }

    unsafe fn newCommandQueue(self) -> id {
        msg_send![self, newCommandQueue]
    }

    #[cfg_attr(rustfmt, rustfmt_skip)] // This definition is too long to fit on one line
    unsafe fn newCommandQueueWithMaxCommandBufferCount(self, maxCommandBufferCount: NSUInteger)
                                                       -> id {
        msg_send![self, newCommandQueueWithMaxCommandBufferCount:maxCommandBufferCount]
    }

    unsafe fn newBufferWithLength_options(self, length: NSUInteger, options: MTLResourceOptions) -> id {
        msg_send![self, newBufferWithLength:length options:options]
    }

    unsafe fn newBufferWithBytes_length_options(self, pointer: *const c_void, length: NSUInteger,
                                                options: MTLResourceOptions)
                                                -> id {
        msg_send![self, newBufferWithBytes:pointer length:length options:options]
    }

    unsafe fn newBufferWithBytesNoCopy_length_options_deallocator(self, pointer: *mut c_void,
                                                                  length: NSUInteger,
                                                                  options: MTLResourceOptions,
                                                                  deallocator: Block<(*mut c_void,
                                                                                NSUInteger),
                                                                                ()>) {
        msg_send![self, newBufferWithBytesNoCopy:pointer
                                          length:length
                                         options:options
                                     deallocator:deallocator]
    }

    unsafe fn newTextureWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newTextureWithDescriptor:descriptor]
    }

    unsafe fn newSamplerStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newSamplerStateWithDescriptor:descriptor]
    }

    unsafe fn newStencilDepthStateWithDescriptor(self, descriptor: id) -> id {
        msg_send![self, newStencilDepthStateWithDescriptor:descriptor]
    }

    unsafe fn newRenderPipleineStateWithDescriptor_completionHandler(
            self, descriptor: id,
            completionHandler: MTLNewRenderPipleineStateCompletionHandler) {
        msg_send![self, newRenderPipleineStateWithDescriptor:descriptor
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_completionHandler(
            self, descriptor: id, options: MTLPipelineOption,
            completionHandler: MTLNewRenderPipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                           completionHandler:completionHandler]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_error(self, descriptor: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor error:error]
    }

    unsafe fn newRenderPipelineStateWithDescriptor_options_reflection(self, descriptor: id,
                                                                      options: MTLPipelineOption,
                                                                      reflection: id, error: id) {
        msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
                                                     options:options
                                                  reflection:reflection
                                                       error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_completionHandler(
                  self,
                  function: id,
                  completionHandler: MTLNewComputePipelineStateCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_options_completionHandler(
            self, function: id, options: MTLPipelineOption,
            completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                          completionHandler:completionHandler]
    }

    unsafe fn newComputePipelineStateWithFunction_error(self, function: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function error:error]
    }

    unsafe fn newComputePipelineStateWithFunction_options_reflection_error(
            self, function: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithFunction:function
                                                    options:options
                                                 reflection:reflection
                                                      error:error]
    }

    unsafe fn newComputePipelineStateWithDescriptor_options_completionHandler(
                   self,
                   descriptor: id,
                   options: MTLPipelineOption,
                   completionHandler: MTLNewComputePipelineStateWithReflectionCompletionHandler) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                            completionHandler:completionHandler]
    }
    unsafe fn newComputePipelineStateWithDescriptor_options_reflection_error(
            self, descriptor: id, options: MTLPipelineOption, reflection: id, error: id) {
        msg_send![self, newComputePipelineStateWithDescriptor:descriptor
                                                      options:options
                                                   reflection:reflection
                                                        error:error]
    }
}

pub type MTLNewLibraryCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipleineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewRenderPipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
pub type MTLNewComputePipelineStateCompletionHandler = Block<(id, id), ()>;
pub type MTLNewComputePipelineStateWithReflectionCompletionHandler = Block<(id, id, id), ()>;
<|endoftext|>


<commit_before>//! Routes are used for ratelimiting. These are to differentiate between the
//! different _types_ of routes - such as getting the current user's channels -
//! for the most part, with the exception being major parameters.
//!
//! [Taken from] the Discord docs, major parameters are:
//!
//! > Additionally, rate limits take into account major parameters in the URL.
//! > For example, `/channels/:channel_id` and
//! > `/channels/:channel_id/messages/:message_id` both take `channel_id` into
//! > account when generating rate limits since it's the major parameter. The
//! only current major parameters are `channel_id` and `guild_id`.
//!
//! This results in the two URIs of `GET /channels/4/messages/7` and
//! `GET /channels/5/messages/8` being rate limited _separately_. However, the
//! two URIs of `GET /channels/10/messages/11` and
//! `GET /channels/10/messages/12` will count towards the "same ratelimit", as
//! the major parameter - `10` is equivilant in both URIs' format.
//!
//! # Examples
//!
//! First: taking the first two URIs - `GET /channels/4/messages/7` and
//! `GET /channels/5/messages/8` - and assuming both buckets have a `limit` of
//! `10`, requesting the first URI will result in the response containing a
//! `remaining` of `9`. Immediately after - prior to buckets resetting -
//! performing a request to the _second_ URI will also contain a `remaining` of
//! `9` in the response, as the major parameter - `channel_id` - is different
//! in the two requests (`4` and `5`).
//!
//! Second: take for example the last two URIs. Assuming the bucket's `limit` is
//! `10`, requesting the first URI will return a `remaining` of `9` in the
//! response. Immediately after - prior to buckets resetting - performing a
//! request to the _second_ URI will return a `remaining` of `8` in the
//! response, as the major parameter - `channel_id` - is equivilant for the two
//! requests (`10`).
//!
//!
//! With the examples out of the way: major parameters are why some variants
//! (i.e. all of the channel/guild variants) have an associated u64 as data.
//! This is the Id of the parameter, differentiating between different
//! ratelimits.

use hyper::client::{RequestBuilder, Response};
use hyper::header::Headers;
use hyper::status::StatusCode;
use std::collections::HashMap;
use std::str;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
use time;
use ::internal::prelude::*;

lazy_static! {
    static ref GLOBAL: Arc<Mutex<RateLimit>> = Arc::new(Mutex::new(RateLimit::default()));
    static ref ROUTES: Arc<Mutex<HashMap<Route, RateLimit>>> = Arc::new(Mutex::new(HashMap::default()));
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Route {
    ChannelsId(u64),
    ChannelsIdInvites(u64),
    ChannelsIdMessages(u64),
    ChannelsIdMessagesBulkDelete(u64),
    ChannelsIdMessagesId(u64),
    ChannelsIdMessagesIdAck(u64),
    ChannelsIdMessagesIdReactions(u64),
    ChannelsIdMessagesIdReactionsUserIdType(u64),
    ChannelsIdPermissionsOverwriteId(u64),
    ChannelsIdPins(u64),
    ChannelsIdPinsMessageId(u64),
    ChannelsIdTyping(u64),
    ChannelsIdWebhooks(u64),
    Gateway,
    GatewayBot,
    Guilds,
    GuildsId(u64),
    GuildsIdBans(u64),
    GuildsIdBansUserId(u64),
    GuildsIdChannels(u64),
    GuildsIdEmbed(u64),
    GuildsIdEmojis(u64),
    GuildsIdEmojisId(u64),
    GuildsIdIntegrations(u64),
    GuildsIdIntegrationsId(u64),
    GuildsIdIntegrationsIdSync(u64),
    GuildsIdInvites(u64),
    GuildsIdMembersId(u64),
    GuildsIdMembersIdRolesId(u64),
    GuildsIdMembersMeNick(u64),
    GuildsIdPrune(u64),
    GuildsIdRegions(u64),
    GuildsIdRoles(u64),
    GuildsIdRolesId(u64),
    GuildsIdWebhooks(u64),
    InvitesCode,
    UsersId,
    UsersMe,
    UsersMeChannels,
    UsersMeConnections,
    UsersMeGuilds,
    UsersMeGuildsId,
    VoiceRegions,
    WebhooksId,
    None,
}

pub fn perform<'a, F>(route: Route, f: F) -> Result<Response>
    where F: Fn() -> RequestBuilder<'a> {

    loop {
        // Perform pre-checking here:
        //
        // - get the route's relevant rate
        // - sleep if that route's already rate-limited until the end of the
        //   'reset' time;
        // - get the global rate;
        // - sleep if there is 0 remaining
        // - then, perform the request
        {
            let mut global = GLOBAL.lock().expect("global route lock poisoned");
            global.pre_hook();
        }

        if route != Route::None {
            if let Some(route) = ROUTES.lock().expect("routes poisoned").get_mut(&route) {
                route.pre_hook();
            }
        }

        let response = try!(super::retry(&f));

        // Check if the request got ratelimited by checking for status 429,
        // and if so, sleep for the value of the header 'retry-after' -
        // which is in milliseconds - and then `continue` to try again
        //
        // If it didn't ratelimit, subtract one from the RateLimit's
        // 'remaining'
        //
        // Update the 'reset' with the value of the 'x-ratelimit-reset'
        // header
        //
        // It _may_ be possible for the limit to be raised at any time,
        // so check if it did from the value of the 'x-ratelimit-limit'
        // header. If the limit was 5 and is now 7, add 2 to the 'remaining'

        if route != Route::None {
            let redo = if response.headers.get_raw("x-ratelimit-global").is_some() {
                let mut global = GLOBAL.lock().expect("global route lock poisoned");
                global.post_hook(&response)
            } else {
                ROUTES.lock()
                    .expect("routes poisoned")
                    .entry(route)
                    .or_insert_with(RateLimit::default)
                    .post_hook(&response)
            };

            if redo.unwrap_or(false) {
                continue;
            }
        }

        return Ok(response);
    }
}

#[derive(Clone, Debug, Default)]
pub struct RateLimit {
    limit: i64,
    remaining: i64,
    reset: i64,
}

impl RateLimit {
    pub fn pre_hook(&mut self) {
        if self.limit == 0 {
            return;
        }

        let current_time = time::get_time().sec;

        // The reset was in the past, so we're probably good.
        if current_time > self.reset {
            self.remaining = self.limit;

            return;
        }

        let diff = (self.reset - current_time) as u64;

        if self.remaining == 0 {
            let delay = (diff * 1000) + 500;

            debug!("Pre-emptive ratelimit for {:?}ms", delay);
            thread::sleep(Duration::from_millis(delay));

            return;
        }

        self.remaining -= 1;
    }

    pub fn post_hook(&mut self, response: &Response) -> Result<bool> {
        if let Some(limit) = try!(get_header(&response.headers, "x-ratelimit-limit")) {
            self.limit = limit;
        }

        if let Some(remaining) = try!(get_header(&response.headers, "x-ratelimit-remaining")) {
            self.remaining = remaining;
        }

        if let Some(reset) = try!(get_header(&response.headers, "x-ratelimit-reset")) {
            self.reset = reset;
        }

        Ok(if response.status != StatusCode::TooManyRequests {
            false
        } else if let Some(retry_after) = try!(get_header(&response.headers, "retry-after")) {
            debug!("Ratelimited: {:?}ms", retry_after);
            thread::sleep(Duration::from_millis(retry_after as u64));

            true
        } else {
            false
        })
    }
}

fn get_header(headers: &Headers, header: &str) -> Result<Option<i64>> {
    match headers.get_raw(header) {
        Some(header) => match str::from_utf8(&header[0]) {
            Ok(v) => match v.parse::<i64>() {
                Ok(v) => Ok(Some(v)),
                Err(_why) => Err(Error::Client(ClientError::RateLimitI64)),
            },
            Err(_why) => Err(Error::Client(ClientError::RateLimitUtf8)),
        },
        None => Ok(None),
    }
}
<commit_msg>Tiny import re-order<commit_after>//! Routes are used for ratelimiting. These are to differentiate between the
//! different _types_ of routes - such as getting the current user's channels -
//! for the most part, with the exception being major parameters.
//!
//! [Taken from] the Discord docs, major parameters are:
//!
//! > Additionally, rate limits take into account major parameters in the URL.
//! > For example, `/channels/:channel_id` and
//! > `/channels/:channel_id/messages/:message_id` both take `channel_id` into
//! > account when generating rate limits since it's the major parameter. The
//! only current major parameters are `channel_id` and `guild_id`.
//!
//! This results in the two URIs of `GET /channels/4/messages/7` and
//! `GET /channels/5/messages/8` being rate limited _separately_. However, the
//! two URIs of `GET /channels/10/messages/11` and
//! `GET /channels/10/messages/12` will count towards the "same ratelimit", as
//! the major parameter - `10` is equivilant in both URIs' format.
//!
//! # Examples
//!
//! First: taking the first two URIs - `GET /channels/4/messages/7` and
//! `GET /channels/5/messages/8` - and assuming both buckets have a `limit` of
//! `10`, requesting the first URI will result in the response containing a
//! `remaining` of `9`. Immediately after - prior to buckets resetting -
//! performing a request to the _second_ URI will also contain a `remaining` of
//! `9` in the response, as the major parameter - `channel_id` - is different
//! in the two requests (`4` and `5`).
//!
//! Second: take for example the last two URIs. Assuming the bucket's `limit` is
//! `10`, requesting the first URI will return a `remaining` of `9` in the
//! response. Immediately after - prior to buckets resetting - performing a
//! request to the _second_ URI will return a `remaining` of `8` in the
//! response, as the major parameter - `channel_id` - is equivilant for the two
//! requests (`10`).
//!
//!
//! With the examples out of the way: major parameters are why some variants
//! (i.e. all of the channel/guild variants) have an associated u64 as data.
//! This is the Id of the parameter, differentiating between different
//! ratelimits.

use hyper::client::{RequestBuilder, Response};
use hyper::header::Headers;
use hyper::status::StatusCode;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::{str, thread};
use time;
use ::internal::prelude::*;

lazy_static! {
    static ref GLOBAL: Arc<Mutex<RateLimit>> = Arc::new(Mutex::new(RateLimit::default()));
    static ref ROUTES: Arc<Mutex<HashMap<Route, RateLimit>>> = Arc::new(Mutex::new(HashMap::default()));
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Route {
    ChannelsId(u64),
    ChannelsIdInvites(u64),
    ChannelsIdMessages(u64),
    ChannelsIdMessagesBulkDelete(u64),
    ChannelsIdMessagesId(u64),
    ChannelsIdMessagesIdAck(u64),
    ChannelsIdMessagesIdReactions(u64),
    ChannelsIdMessagesIdReactionsUserIdType(u64),
    ChannelsIdPermissionsOverwriteId(u64),
    ChannelsIdPins(u64),
    ChannelsIdPinsMessageId(u64),
    ChannelsIdTyping(u64),
    ChannelsIdWebhooks(u64),
    Gateway,
    GatewayBot,
    Guilds,
    GuildsId(u64),
    GuildsIdBans(u64),
    GuildsIdBansUserId(u64),
    GuildsIdChannels(u64),
    GuildsIdEmbed(u64),
    GuildsIdEmojis(u64),
    GuildsIdEmojisId(u64),
    GuildsIdIntegrations(u64),
    GuildsIdIntegrationsId(u64),
    GuildsIdIntegrationsIdSync(u64),
    GuildsIdInvites(u64),
    GuildsIdMembersId(u64),
    GuildsIdMembersIdRolesId(u64),
    GuildsIdMembersMeNick(u64),
    GuildsIdPrune(u64),
    GuildsIdRegions(u64),
    GuildsIdRoles(u64),
    GuildsIdRolesId(u64),
    GuildsIdWebhooks(u64),
    InvitesCode,
    UsersId,
    UsersMe,
    UsersMeChannels,
    UsersMeConnections,
    UsersMeGuilds,
    UsersMeGuildsId,
    VoiceRegions,
    WebhooksId,
    None,
}

pub fn perform<'a, F>(route: Route, f: F) -> Result<Response>
    where F: Fn() -> RequestBuilder<'a> {

    loop {
        // Perform pre-checking here:
        //
        // - get the route's relevant rate
        // - sleep if that route's already rate-limited until the end of the
        //   'reset' time;
        // - get the global rate;
        // - sleep if there is 0 remaining
        // - then, perform the request
        {
            let mut global = GLOBAL.lock().expect("global route lock poisoned");
            global.pre_hook();
        }

        if route != Route::None {
            if let Some(route) = ROUTES.lock().expect("routes poisoned").get_mut(&route) {
                route.pre_hook();
            }
        }

        let response = try!(super::retry(&f));

        // Check if the request got ratelimited by checking for status 429,
        // and if so, sleep for the value of the header 'retry-after' -
        // which is in milliseconds - and then `continue` to try again
        //
        // If it didn't ratelimit, subtract one from the RateLimit's
        // 'remaining'
        //
        // Update the 'reset' with the value of the 'x-ratelimit-reset'
        // header
        //
        // It _may_ be possible for the limit to be raised at any time,
        // so check if it did from the value of the 'x-ratelimit-limit'
        // header. If the limit was 5 and is now 7, add 2 to the 'remaining'

        if route != Route::None {
            let redo = if response.headers.get_raw("x-ratelimit-global").is_some() {
                let mut global = GLOBAL.lock().expect("global route lock poisoned");
                global.post_hook(&response)
            } else {
                ROUTES.lock()
                    .expect("routes poisoned")
                    .entry(route)
                    .or_insert_with(RateLimit::default)
                    .post_hook(&response)
            };

            if redo.unwrap_or(false) {
                continue;
            }
        }

        return Ok(response);
    }
}

#[derive(Clone, Debug, Default)]
pub struct RateLimit {
    limit: i64,
    remaining: i64,
    reset: i64,
}

impl RateLimit {
    pub fn pre_hook(&mut self) {
        if self.limit == 0 {
            return;
        }

        let current_time = time::get_time().sec;

        // The reset was in the past, so we're probably good.
        if current_time > self.reset {
            self.remaining = self.limit;

            return;
        }

        let diff = (self.reset - current_time) as u64;

        if self.remaining == 0 {
            let delay = (diff * 1000) + 500;

            debug!("Pre-emptive ratelimit for {:?}ms", delay);
            thread::sleep(Duration::from_millis(delay));

            return;
        }

        self.remaining -= 1;
    }

    pub fn post_hook(&mut self, response: &Response) -> Result<bool> {
        if let Some(limit) = try!(get_header(&response.headers, "x-ratelimit-limit")) {
            self.limit = limit;
        }

        if let Some(remaining) = try!(get_header(&response.headers, "x-ratelimit-remaining")) {
            self.remaining = remaining;
        }

        if let Some(reset) = try!(get_header(&response.headers, "x-ratelimit-reset")) {
            self.reset = reset;
        }

        Ok(if response.status != StatusCode::TooManyRequests {
            false
        } else if let Some(retry_after) = try!(get_header(&response.headers, "retry-after")) {
            debug!("Ratelimited: {:?}ms", retry_after);
            thread::sleep(Duration::from_millis(retry_after as u64));

            true
        } else {
            false
        })
    }
}

fn get_header(headers: &Headers, header: &str) -> Result<Option<i64>> {
    match headers.get_raw(header) {
        Some(header) => match str::from_utf8(&header[0]) {
            Ok(v) => match v.parse::<i64>() {
                Ok(v) => Ok(Some(v)),
                Err(_why) => Err(Error::Client(ClientError::RateLimitI64)),
            },
            Err(_why) => Err(Error::Client(ClientError::RateLimitUtf8)),
        },
        None => Ok(None),
    }
}
<|endoftext|>


<commit_before>use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline(always)]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline(always)]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline(always)]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a mut self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub struct SegmentReader<'self> {
    messageReader : &'self MessageReader<'self>,
    segment : &'self [u8]
}<commit_msg>starting MessageBuilders<commit_after>use std;
use common::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline(always)]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline(always)]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline(always)]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a mut self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub struct SegmentReader<'self> {
    messageReader : &'self MessageReader<'self>,
    segment : &'self [u8]
}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub struct MallocMessageBuilder {
    nextSize : uint,
    firstSegment : ~[u8],
    moreSegments : Option<~[~[u8]]>
}

impl MallocMessageBuilder {
    pub fn new(firstSegment : ~[u8], allocationStrategy : AllocationStrategy)
        -> MallocMessageBuilder {
        MallocMessageBuilder {
            nextSize : firstSegment.len(),
            firstSegment : firstSegment,
            moreSegments : None
        }
    }

    pub fn new_default() -> MallocMessageBuilder {
        MallocMessageBuilder {
            nextSize : SUGGESTED_FIRST_SEGMENT_WORDS,
            firstSegment : std::vec::from_elem(SUGGESTED_FIRST_SEGMENT_WORDS * BYTES_PER_WORD,
                                               0),
            moreSegments : None
        }
    }

}<|endoftext|>


<commit_before>use sfml::graphics;
use sfml::graphics::{Color, RenderTarget, Vertex, VertexArray};
use sfml::system::Vector2f;
use na::Point2;
use nphysics2d::world::World;

pub static DRAW_SCALE: f32 = 20.0;

pub fn draw_colls(window: &mut graphics::RenderWindow, world: &World<f32>) {
    for (_, _, manifold) in world.collision_world().contact_manifolds() {
        for c in manifold.contacts() {
            draw_line(
                window,
                &c.contact.world1,
                &c.contact.world2,
                &Color::new_rgb(255, 0, 0),
            );
        }
    }
}

pub fn draw_line(
    window: &mut graphics::RenderWindow,
    v1: &Point2<f32>,
    v2: &Point2<f32>,
    color: &Color,
) {
    let mut vertices = VertexArray::new().unwrap();

    vertices.append(&Vertex::new(
        &Vector2f::new(v1.x * DRAW_SCALE, v1.y * DRAW_SCALE),
        color,
        &Vector2f::new(0.0, 0.0),
    ));

    vertices.append(&Vertex::new(
        &Vector2f::new(v2.x * DRAW_SCALE, v2.y * DRAW_SCALE),
        color,
        &Vector2f::new(0.0, 0.0),
    ));

    vertices.set_primitive_type(graphics::Lines);

    window.draw(&vertices);
}
<commit_msg>Testbed: color in green contact point with a point-point contact kinematic.<commit_after>use sfml::graphics;
use sfml::graphics::{Color, RenderTarget, Vertex, VertexArray};
use sfml::system::Vector2f;
use na::Point2;
use ncollide::query::ContactKinematic;
use nphysics2d::world::World;

pub static DRAW_SCALE: f32 = 20.0;

pub fn draw_colls(window: &mut graphics::RenderWindow, world: &World<f32>) {
    for (_, _, manifold) in world.collision_world().contact_manifolds() {
        for c in manifold.contacts() {
            let color = if c.kinematic == ContactKinematic::PointPoint {
                Color::new_rgb(0, 255, 0)
            } else {
                Color::new_rgb(255, 0, 0)
            };
            draw_line(window, &c.contact.world1, &c.contact.world2, &color);
        }
    }
}

pub fn draw_line(
    window: &mut graphics::RenderWindow,
    v1: &Point2<f32>,
    v2: &Point2<f32>,
    color: &Color,
) {
    let mut vertices = VertexArray::new().unwrap();

    vertices.append(&Vertex::new(
        &Vector2f::new(v1.x * DRAW_SCALE, v1.y * DRAW_SCALE),
        color,
        &Vector2f::new(0.0, 0.0),
    ));

    vertices.append(&Vertex::new(
        &Vector2f::new(v2.x * DRAW_SCALE, v2.y * DRAW_SCALE),
        color,
        &Vector2f::new(0.0, 0.0),
    ));

    vertices.set_primitive_type(graphics::Lines);

    window.draw(&vertices);
}
<|endoftext|>


<commit_before><commit_msg>rust - fix compiler warnings<commit_after><|endoftext|>


<commit_before>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

fn setup_logging(logging_path_result: Result<PathBuf, io::Error>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Ok(logging_file_path) = &logging_path_result {
        // Ensure the logging directory is created
        let parent_path = logging_file_path.parent().ok_or(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "Unable to get the parent of the following Path: {}",
                logging_file_path.display(),
            ),
        ))?;
        fs::create_dir_all(parent_path)?;
        // Attach it to fern
        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is setup");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match &logging_path_result {
        Ok(logging_file_path) => {
            info!(
                "Logging to the following file: {}",
                logging_file_path.display()
            );
        }
        Err(e) => {
            let message = "There was an issue getting the path for the log file";
            warn!("{}: {:?}, falling back to stderr.", message, e);
        }
    }
    Ok(())
}

fn prepare_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => XI_LOG_FILE.to_string(),
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => XI_LOG_DIR.to_string(),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

struct LogfileConfig {
    directory: Option<String>,
    file: Option<String>,
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_itterator = std::env::args().peekable();
    while let Some(arg) = args_itterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_itterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_itterator.next());
            }
        }
    }
    flags
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags: HashMap<String, Option<String>> = get_flags();

    // If the key is set, get the Option within
    let log_dir_flag_option = flags.get("log-dir").cloned().unwrap_or(None);
    let log_file_flag_option = flags.get("log-file").cloned().unwrap_or(None);

    let logfile_config = LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    };

    let logging_path: Result<PathBuf, io::Error> = prepare_logging_path(logfile_config);
    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging disabled: {:?}",
            e
        );
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<commit_msg>Moved LogfileConfig generation to a separate function.<commit_after>// Copyright 2016 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate log;
extern crate chrono;
extern crate fern;

extern crate dirs;

extern crate xi_core_lib;
extern crate xi_rpc;

use std::collections::HashMap;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use xi_core_lib::XiCore;
use xi_rpc::RpcLoop;

const XI_LOG_DIR: &str = "xi-core";
const XI_LOG_FILE: &str = "xi-core.log";

fn get_logging_directory_path<P: AsRef<Path>>(directory: P) -> Result<PathBuf, io::Error> {
    match dirs::data_local_dir() {
        Some(mut log_dir) => {
            log_dir.push(directory);
            Ok(log_dir)
        }
        None => Err(io::Error::new(
            io::ErrorKind::NotFound,
            "No standard logging directory known for this platform",
        )),
    }
}

fn setup_logging(logging_path_result: Result<PathBuf, io::Error>) -> Result<(), fern::InitError> {
    let level_filter = match std::env::var("XI_LOG") {
        Ok(level) => match level.to_lowercase().as_ref() {
            "trace" => log::LevelFilter::Trace,
            "debug" => log::LevelFilter::Debug,
            _ => log::LevelFilter::Info,
        },
        // Default to info
        Err(_) => log::LevelFilter::Info,
    };

    let mut fern_dispatch = fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!(
                "{}[{}][{}] {}",
                chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
                record.target(),
                record.level(),
                message,
            ))
        }).level(level_filter)
        .chain(io::stderr());

    if let Ok(logging_file_path) = &logging_path_result {
        // Ensure the logging directory is created
        let parent_path = logging_file_path.parent().ok_or(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "Unable to get the parent of the following Path: {}",
                logging_file_path.display(),
            ),
        ))?;
        fs::create_dir_all(parent_path)?;
        // Attach it to fern
        fern_dispatch = fern_dispatch.chain(fern::log_file(logging_file_path)?);
    };

    // Start fern
    fern_dispatch.apply()?;
    info!("Logging with fern is setup");

    // Log details of the logging_file_path result using fern/log
    // Either logging the path fern is outputting to or the error from obtaining the path
    match &logging_path_result {
        Ok(logging_file_path) => {
            info!(
                "Logging to the following file: {}",
                logging_file_path.display()
            );
        }
        Err(e) => {
            let message = "There was an issue getting the path for the log file";
            warn!("{}: {:?}, falling back to stderr.", message, e);
        }
    }
    Ok(())
}

fn prepare_logging_path(logfile_config: LogfileConfig) -> Result<PathBuf, io::Error> {
    // Use the file name set in logfile_config or fallback to the default
    let logfile_file_name = match logfile_config.file {
        Some(file_name) => file_name,
        None => XI_LOG_FILE.to_string(),
    };
    // Use the directory name set in logfile_config or fallback to the default
    let logfile_directory_name = match logfile_config.directory {
        Some(dir) => dir,
        None => XI_LOG_DIR.to_string(),
    };

    let mut logging_directory_path = get_logging_directory_path(logfile_directory_name)?;

    // Add the file name & return the full path
    logging_directory_path.push(logfile_file_name);
    Ok(logging_directory_path)
}

struct LogfileConfig {
    directory: Option<String>,
    file: Option<String>,
}

fn get_flags() -> HashMap<String, Option<String>> {
    let mut flags: HashMap<String, Option<String>> = HashMap::new();

    let flag_prefix = "-";
    let mut args_itterator = std::env::args().peekable();
    while let Some(arg) = args_itterator.next() {
        if arg.starts_with(flag_prefix) {
            let key = arg.trim_left_matches(flag_prefix).to_string();

            // Check the next argument doesn't start with the flag prefix
            // map_or accounts for peek returning an Option
            let next_arg_not_a_flag: bool = args_itterator
                .peek()
                .map_or(false, |val| !val.starts_with(flag_prefix));
            if next_arg_not_a_flag {
                flags.insert(key, args_itterator.next());
            }
        }
    }
    flags
}

fn generate_logfile_config(flags: HashMap<String, Option<String>>) -> LogfileConfig {
    // If the key is set, get the Option within
    let log_dir_flag_option = flags.get("log-dir").cloned().unwrap_or(None);
    let log_file_flag_option = flags.get("log-file").cloned().unwrap_or(None);

    LogfileConfig {
        directory: log_dir_flag_option,
        file: log_file_flag_option,
    }
}

fn main() {
    let mut state = XiCore::new();
    let stdin = io::stdin();
    let stdout = io::stdout();
    let mut rpc_looper = RpcLoop::new(stdout);

    let flags: HashMap<String, Option<String>> = get_flags();

    let logfile_config = generate_logfile_config(flags);

    let logging_path: Result<PathBuf, io::Error> = prepare_logging_path(logfile_config);
    if let Err(e) = setup_logging(logging_path) {
        eprintln!(
            "[ERROR] setup_logging returned error, logging disabled: {:?}",
            e
        );
    }

    match rpc_looper.mainloop(|| stdin.lock(), &mut state) {
        Ok(_) => (),
        Err(err) => error!("xi-core exited with error:\n{:?}", err),
    }
}
<|endoftext|>