<commit_before>//! Binding to [TensorFlow][1].
//!
//! [1]: https://www.tensorflow.org

#![allow(non_camel_case_types)]

extern crate libc;

use libc::{c_char, c_uchar, c_int, c_void, int64_t, size_t, c_float};

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct TF_Buffer {
    pub data: *const c_void,
    pub length: size_t,
    pub data_deallocator: Option<unsafe extern "C" fn(data: *mut c_void, length: size_t)>,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TF_Code {
    TF_OK = 0,
    TF_CANCELLED = 1,
    TF_UNKNOWN = 2,
    TF_INVALID_ARGUMENT = 3,
    TF_DEADLINE_EXCEEDED = 4,
    TF_NOT_FOUND = 5,
    TF_ALREADY_EXISTS = 6,
    TF_PERMISSION_DENIED = 7,
    TF_UNAUTHENTICATED = 16,
    TF_RESOURCE_EXHAUSTED = 8,
    TF_FAILED_PRECONDITION = 9,
    TF_ABORTED = 10,
    TF_OUT_OF_RANGE = 11,
    TF_UNIMPLEMENTED = 12,
    TF_INTERNAL = 13,
    TF_UNAVAILABLE = 14,
    TF_DATA_LOSS = 15,
}
pub use TF_Code::*;

#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TF_DataType {
    TF_FLOAT = 1,
    TF_DOUBLE = 2,
    TF_INT32 = 3,
    TF_UINT8 = 4,
    TF_INT16 = 5,
    TF_INT8 = 6,
    TF_STRING = 7,
    TF_COMPLEX64 = 8,
    TF_INT64 = 9,
    TF_BOOL = 10,
    TF_QINT8 = 11,
    TF_QUINT8 = 12,
    TF_QINT32 = 13,
    TF_BFLOAT16 = 14,
    TF_QINT16 = 15,
    TF_QUINT16 = 16,
    TF_UINT16 = 17,
    TF_COMPLEX128 = 18,
    TF_HALF = 19,
    TF_RESOURCE = 20,
}
pub use TF_DataType::*;

#[derive(Clone, Copy, Debug)]
pub enum TF_Library {}

#[derive(Clone, Copy, Debug)]
#[deprecated(since="0.5.0", note="Use TF_Session instead.")]
pub enum TF_DeprecatedSession {}

#[derive(Clone, Copy, Debug)]
pub enum TF_SessionOptions {}

#[derive(Clone, Copy, Debug)]
pub enum TF_Status {}

#[derive(Clone, Copy, Debug)]
pub enum TF_Tensor {}

#[derive(Clone, Copy, Debug)]
pub enum TF_Graph {}

#[derive(Clone, Copy, Debug)]
pub enum TF_OperationDescription {}

#[derive(Clone, Copy, Debug)]
pub enum TF_Operation {}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct TF_Input {
    pub operation: *mut TF_Operation,
    pub index: c_int,
}

#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct TF_Output {
    pub operation: *mut TF_Operation,
    pub index: c_int,
}

#[derive(Clone, Copy, Debug)]
pub enum TF_Session {}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(C)]
pub enum TF_AttrType {
    TF_ATTR_STRING = 0,
    TF_ATTR_INT = 1,
    TF_ATTR_FLOAT = 2,
    TF_ATTR_BOOL = 3,
    TF_ATTR_TYPE = 4,
    TF_ATTR_SHAPE = 5,
    TF_ATTR_TENSOR = 6,
    TF_ATTR_PLACEHOLDER = 7,
    TF_ATTR_FUNC = 8,
}
pub use TF_AttrType::*;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(C)]
pub struct TF_AttrMetadata {
    pub is_list: c_uchar,
    pub list_size: int64_t,
    pub type_: TF_AttrType,
    pub total_size: int64_t,
}

#[derive(Clone, Copy, Debug)]
pub enum TF_ImportGraphDefOptions {}

extern "C" {
    pub fn TF_NewBuffer() -> *mut TF_Buffer;
    pub fn TF_NewBufferFromString(proto: *const c_void, length: size_t) -> *mut TF_Buffer;
    pub fn TF_DeleteBuffer(buffer: *mut TF_Buffer);
    pub fn TF_GetBuffer(buffer: *mut TF_Buffer) -> TF_Buffer;
}

extern "C" {
    pub fn TF_LoadLibrary(name: *const c_char, status: *mut TF_Status) -> *mut TF_Library;
    pub fn TF_DeleteLibraryHandle(lib_handle: *mut TF_Library);
    pub fn TF_GetOpList(library: *mut TF_Library) -> TF_Buffer;
    pub fn TF_GetAllOpList() -> *mut TF_Buffer;
}

extern "C" {
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_NewSession instead.")]
    pub fn TF_NewDeprecatedSession(options: *const TF_SessionOptions,
                                   status: *mut TF_Status)
                                   -> *mut TF_DeprecatedSession;
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_DeleteSession instead.")]
    pub fn TF_DeleteDeprecatedSession(session: *mut TF_DeprecatedSession, status: *mut TF_Status);
    pub fn TF_Reset(opt: *const TF_SessionOptions,
                    containers: *const *const c_char,
                    ncontainers: c_int,
                    status: *mut TF_Status);
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_CloseSession instead.")]
    pub fn TF_CloseDeprecatedSession(session: *mut TF_DeprecatedSession, status: *mut TF_Status);
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_Session API instead.")]
    pub fn TF_ExtendGraph(session: *mut TF_DeprecatedSession,
                          proto: *const c_void,
                          length: size_t,
                          status: *mut TF_Status);
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_SessionRun instead.")]
    pub fn TF_Run(session: *mut TF_DeprecatedSession,
                  run_options: *const TF_Buffer,
                  input_names: *mut *const c_char,
                  inputs: *mut *mut TF_Tensor,
                  ninputs: c_int,
                  output_names: *mut *const c_char,
                  outputs: *mut *mut TF_Tensor,
                  noutputs: c_int,
                  target_names: *mut *const c_char,
                  ntargets: c_int,
                  run_metadata: *mut TF_Buffer,
                  status: *mut TF_Status);
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_SessionPRunSetup instead.")]
    pub fn TF_PRunSetup(session: *mut TF_DeprecatedSession,
                        input_names: *mut *const c_char,
                        ninputs: c_int,
                        output_names: *mut *const c_char,
                        noutputs: c_int,
                        target_names: *mut *const c_char,
                        ntargets: c_int,
                        handle: *mut *const c_char,
                        status: *mut TF_Status);
    #[allow(deprecated)]
    #[deprecated(since="0.5.0", note="Use TF_SessionPRun instead.")]
    pub fn TF_PRun(session: *mut TF_DeprecatedSession,
                   handle: *const c_char,
                   input_names: *mut *const c_char,
                   inputs: *mut *mut TF_Tensor,
                   ninputs: c_int,
                   output_names: *mut *const c_char,
                   outputs: *mut *mut TF_Tensor,
                   noutputs: c_int,
                   target_names: *mut *const c_char,
                   ntargets: c_int,
                   status: *mut TF_Status);
}

extern "C" {
    pub fn TF_NewSessionOptions() -> *mut TF_SessionOptions;
    pub fn TF_DeleteSessionOptions(options: *mut TF_SessionOptions);
    pub fn TF_SetTarget(options: *mut TF_SessionOptions, target: *const c_char);
    pub fn TF_SetConfig(options: *mut TF_SessionOptions,
                        proto: *const c_void,
                        length: size_t,
                        status: *mut TF_Status);
}

extern "C" {
    pub fn TF_NewStatus() -> *mut TF_Status;
    pub fn TF_DeleteStatus(status: *mut TF_Status);
    pub fn TF_SetStatus(status: *mut TF_Status, code: TF_Code, message: *const c_char);
    pub fn TF_GetCode(status: *const TF_Status) -> TF_Code;
    pub fn TF_Message(status: *const TF_Status) -> *const c_char;
}

extern "C" {
    pub fn TF_NewTensor(datatype: TF_DataType,
                        dims: *const int64_t,
                        ndims: c_int,
                        data: *mut c_void,
                        length: size_t,
                        deallocator: Option<unsafe extern "C" fn(data: *mut c_void,
                                                                 length: size_t,
                                                                 arg: *mut c_void)>,
                        deallocator_arg: *mut c_void)
                        -> *mut TF_Tensor;
    pub fn TF_AllocateTensor(datatype: TF_DataType,
                             dims: *const int64_t,
                             num_dims: c_int,
                             len: size_t)
                             -> *mut TF_Tensor;
    pub fn TF_DeleteTensor(tensor: *mut TF_Tensor);
    pub fn TF_TensorType(tensor: *const TF_Tensor) -> TF_DataType;
    pub fn TF_NumDims(tensor: *const TF_Tensor) -> c_int;
    pub fn TF_Dim(tensor: *const TF_Tensor, index: c_int) -> int64_t;
    pub fn TF_TensorByteSize(tensor: *const TF_Tensor) -> size_t;
    pub fn TF_TensorData(tensor: *const TF_Tensor) -> *mut c_void;
}

extern "C" {
    pub fn TF_NewGraph() -> *mut TF_Graph;
    pub fn TF_DeleteGraph(graph: *mut TF_Graph);
    pub fn TF_NewOperation(graph: *mut TF_Graph,
                           op_type: *const c_char,
                           operation_name: *const c_char)
                           -> *mut TF_OperationDescription;
    pub fn TF_SetDevice(desc: *mut TF_OperationDescription, device: *const c_char);
    pub fn TF_AddInput(desc: *mut TF_OperationDescription, input: TF_Output);
    pub fn TF_AddInputList(desc: *mut TF_OperationDescription,
                           inputs: *const TF_Output,
                           num_inputs: c_int);
    pub fn TF_AddControlInput(desc: *mut TF_OperationDescription, input: *mut TF_Operation);
    pub fn TF_SetAttrString(desc: *mut TF_OperationDescription,
                            attr_name: *const c_char,
                            value: *const c_void,
                            length: size_t);
    pub fn TF_SetAttrStringList(desc: *mut TF_OperationDescription,
                                attr_name: *const c_char,
                                values: *const *const c_void,
                                lengths: *const size_t,
                                num_values: c_int);
    pub fn TF_SetAttrInt(desc: *mut TF_OperationDescription,
                         attr_name: *const c_char,
                         value: int64_t);
    pub fn TF_SetAttrIntList(desc: *mut TF_OperationDescription,
                             attr_name: *const c_char,
                             values: *const int64_t,
                             num_values: c_int);
    pub fn TF_SetAttrFloat(desc: *mut TF_OperationDescription,
                           attr_name: *const c_char,
                           value: c_float);
    pub fn TF_SetAttrFloatList(desc: *mut TF_OperationDescription,
                               attr_name: *const c_char,
                               values: *const c_float,
                               num_values: c_int);
    pub fn TF_SetAttrBool(desc: *mut TF_OperationDescription,
                          attr_name: *const c_char,
                          value: c_uchar);
    pub fn TF_SetAttrBoolList(desc: *mut TF_OperationDescription,
                              attr_name: *const c_char,
                              values: *const c_uchar,
                              num_values: c_int);
    pub fn TF_SetAttrType(desc: *mut TF_OperationDescription,
                          attr_name: *const c_char,
                          value: TF_DataType);
    pub fn TF_SetAttrTypeList(desc: *mut TF_OperationDescription,
                              attr_name: *const c_char,
                              values: *const TF_DataType,
                              num_values: c_int);
    pub fn TF_SetAttrShape(desc: *mut TF_OperationDescription,
                           attr_name: *const c_char,
                           dims: *const int64_t,
                           num_dims: c_int);
    pub fn TF_SetAttrShapeList(desc: *mut TF_OperationDescription,
                               attr_name: *const c_char,
                               dims: *const *const int64_t,
                               num_dims: *const c_int,
                               num_shapes: c_int);
    pub fn TF_SetAttrTensorShapeProto(desc: *mut TF_OperationDescription,
                                      attr_name: *const c_char,
                                      proto: *const c_void,
                                      proto_len: size_t,
                                      status: *mut TF_Status);
    pub fn TF_SetAttrTensorShapeProtoList(desc: *mut TF_OperationDescription,
                                          attr_name: *const c_char,
                                          protos: *const *const c_void,
                                          proto_lens: *const size_t,
                                          num_shapes: c_int,
                                          status: *mut TF_Status);
    pub fn TF_SetAttrTensor(desc: *mut TF_OperationDescription,
                            attr_name: *const c_char,
                            value: *mut TF_Tensor,
                            status: *mut TF_Status);
    pub fn TF_SetAttrTensorList(desc: *mut TF_OperationDescription,
                                attr_name: *const c_char,
                                values: *const *mut TF_Tensor,
                                num_values: c_int,
                                status: *mut TF_Status);
    pub fn TF_SetAttrValueProto(desc: *mut TF_OperationDescription,
                                attr_name: *const c_char,
                                proto: *const c_void,
                                proto_len: size_t,
                                status: *mut TF_Status);
    pub fn TF_FinishOperation(desc: *mut TF_OperationDescription,
                              status: *mut TF_Status)
                              -> *mut TF_Operation;
    pub fn TF_OperationName(operation: *mut TF_Operation) -> *const c_char;
    pub fn TF_OperationOpType(operation: *mut TF_Operation) -> *const c_char;
    pub fn TF_OperationDevice(operation: *mut TF_Operation) -> *const c_char;
    pub fn TF_OperationNumOutputs(operation: *mut TF_Operation) -> c_int;
    pub fn TF_OperationOutputType(operation_out: TF_Output) -> TF_DataType;
    pub fn TF_OperationOutputListLength(operation: *mut TF_Operation,
                                        arg_name: *const c_char,
                                        status: *mut TF_Status)
                                        -> c_int;
    pub fn TF_OperationNumInputs(operation: *mut TF_Operation) -> c_int;
    pub fn TF_OperationInputType(operation_in: TF_Input) -> TF_DataType;
    pub fn TF_OperationInputListLength(operation: *mut TF_Operation,
                                       arg_name: *const c_char,
                                       status: *mut TF_Status)
                                       -> c_int;
    pub fn TF_OperationInput(operation_in: TF_Input) -> TF_Output;
    pub fn TF_OperationOutputNumConsumers(operation_out: TF_Output) -> c_int;
    pub fn TF_OperationOutputConsumers(operation_out: TF_Output,
                                       consumers: *mut TF_Input,
                                       max_consumers: c_int)
                                       -> c_int;
    pub fn TF_OperationNumControlInputs(operation: *mut TF_Operation) -> c_int;
    pub fn TF_OperationGetControlInputs(operation: *mut TF_Operation,
                                        control_inputs: *mut *mut TF_Operation,
                                        max_control_inputs: c_int)
                                        -> c_int;
    pub fn TF_OperationNumControlOutputs(operation: *mut TF_Operation) -> c_int;
    pub fn TF_OperationGetControlOutputs(operation: *mut TF_Operation,
                                         control_outputs: *mut *mut TF_Operation,
                                         max_control_outputs: c_int)
                                         -> c_int;
    pub fn TF_OperationGetAttrValueProto(operation: *mut TF_Operation,
                                         attr_name: *const c_char,
                                         output_attr_value: *mut TF_Buffer,
                                         status: *mut TF_Status);
    pub fn TF_GraphOperationByName(graph: *mut TF_Graph,
                                   operation_name: *const c_char)
                                   -> *mut TF_Operation;
    pub fn TF_GraphNextOperation(graph: *mut TF_Graph, pos: *mut size_t) -> *mut TF_Operation;
    pub fn TF_GraphToGraphDef(graph: *mut TF_Graph,
                              output_graph_def: *mut TF_Buffer,
                              status: *mut TF_Status);
    pub fn TF_OperationToNodeDef(operation: *mut TF_Operation,
                                 output_operation_def: *mut TF_Buffer,
                                 status: *mut TF_Status);
    pub fn TF_GraphSetTensorShape(graph: *mut TF_Graph,
                                  output: TF_Output,
                                  dims: *const int64_t,
                                  num_dims: c_int,
                                  status: *mut TF_Status);
    pub fn TF_GraphGetTensorNumDims(graph: *const TF_Graph,
                                    output: TF_Output,
                                    status: *mut TF_Status)
                                    -> c_int;
    pub fn TF_GraphGetTensorShape(graph: *const TF_Graph,
                                  output: TF_Output,
                                  dims: *mut int64_t,
                                  num_dims: c_int,
                                  status: *mut TF_Status);
    pub fn TF_ColocateWith(desc: *mut TF_OperationDescription, op: *mut TF_Operation);
    pub fn TF_OperationGetAttrMetadata(oper: *const TF_Operation,
                                       attr_name: *const c_char,
                                       status: *mut TF_Status)
                                       -> TF_AttrMetadata;
    pub fn TF_OperationGetAttrString(oper: *const TF_Operation,
                                     attr_name: *const c_char,
                                     value: *mut c_void,
                                     max_length: size_t,
                                     status: *mut TF_Status);
    pub fn TF_OperationGetAttrStringList(oper: *const TF_Operation,
                                         attr_name: *const c_char,
                                         values: *mut *mut c_void,
                                         lengths: *mut size_t,
                                         max_values: c_int,
                                         storage: *mut c_void,
                                         storage_size: size_t,
                                         status: *mut TF_Status);
    pub fn TF_OperationGetAttrInt(oper: *const TF_Operation,
                                  attr_name: *const c_char,
                                  value: *mut int64_t,
                                  status: *mut TF_Status);
    pub fn TF_OperationGetAttrIntList(oper: *const TF_Operation,
                                      attr_name: *const c_char,
                                      values: *mut int64_t,
                                      max_values: c_int,
                                      status: *mut TF_Status);
    pub fn TF_OperationGetAttrFloat(oper: *const TF_Operation,
                                    attr_name: *const c_char,
                                    value: *mut c_float,
                                    status: *mut TF_Status);
    pub fn TF_OperationGetAttrFloatList(oper: *const TF_Operation,
                                        attr_name: *const c_char,
                                        values: *mut c_float,
                                        max_values: c_int,
                                        status: *mut TF_Status);
    pub fn TF_OperationGetAttrBool(oper: *const TF_Operation,
                                   attr_name: *const c_char,
                                   value: *mut c_uchar,
                                   status: *mut TF_Status);
    pub fn TF_OperationGetAttrBoolList(oper: *const TF_Operation,
                                       attr_name: *const c_char,
                                       values: *mut c_uchar,
                                       max_values: c_int,
                                       status: *mut TF_Status);
    pub fn TF_OperationGetAttrType(oper: *const TF_Operation,
                                   attr_name: *const c_char,
                                   value: *mut TF_DataType,
                                   status: *mut TF_Status);
    pub fn TF_OperationGetAttrTypeList(oper: *const TF_Operation,
                                       attr_name: *const c_char,
                                       values: *mut TF_DataType,
                                       max_values: c_int,
                                       status: *mut TF_Status);
    pub fn TF_OperationGetAttrShape(oper: *const TF_Operation,
                                    attr_name: *const c_char,
                                    value: *mut int64_t,
                                    num_dims: c_int,
                                    status: *mut TF_Status);
    pub fn TF_OperationGetAttrShapeList(oper: *const TF_Operation,
                                        attr_name: *const c_char,
                                        dims: *mut *mut int64_t,
                                        num_dims: *mut c_int,
                                        num_shapes: c_int,
                                        storage: *mut int64_t,
                                        storage_size: c_int,
                                        status: *mut TF_Status);
    pub fn TF_OperationGetAttrTensorShapeProto(oper: *const TF_Operation,
                                               attr_name: *const c_char,
                                               value: *mut TF_Buffer,
                                               status: *mut TF_Status);
    pub fn TF_OperationGetAttrTensorShapeProtoList(oper: *const TF_Operation,
                                                   attr_name: *const c_char,
                                                   values: *mut *mut TF_Buffer,
                                                   max_values: c_int,
                                                   status: *mut TF_Status);
    pub fn TF_OperationGetAttrTensor(oper: *const TF_Operation,
                                     attr_name: *const c_char,
                                     value: *mut *mut TF_Tensor,
                                     status: *mut TF_Status);
    pub fn TF_OperationGetAttrTensorList(oper: *const TF_Operation,
                                         attr_name: *const c_char,
                                         values: *mut *mut TF_Tensor,
                                         max_values: c_int,
                                         status: *mut TF_Status);
    pub fn TF_NewImportGraphDefOptions() -> *mut TF_ImportGraphDefOptions;
    pub fn TF_DeleteImportGraphDefOptions(opts: *mut TF_ImportGraphDefOptions);
    pub fn TF_ImportGraphDefOptionsSetPrefix(opts: *mut TF_ImportGraphDefOptions,
                                             prefix: *const c_char);
    pub fn TF_GraphImportGraphDef(graph: *mut TF_Graph,
                                  graph_def: *const TF_Buffer,
                                  options: *const TF_ImportGraphDefOptions,
                                  status: *mut TF_Status);
}

extern "C" {
    pub fn TF_NewSession(graph: *mut TF_Graph,
                         opts: *const TF_SessionOptions,
                         status: *mut TF_Status)
                         -> *mut TF_Session;
    pub fn TF_CloseSession(session: *mut TF_Session, status: *mut TF_Status);
    pub fn TF_DeleteSession(session: *mut TF_Session, status: *mut TF_Status);
    pub fn TF_SessionRun(session: *mut TF_Session,
                         run_options: *const TF_Buffer,
                         inputs: *const TF_Output,
                         input_values: *const *mut TF_Tensor,
                         ninputs: c_int,
                         outputs: *const TF_Output,
                         output_values: *mut *mut TF_Tensor,
                         noutputs: c_int,
                         target_operations: *const *const TF_Operation,
                         ntargets: c_int,
                         run_metadata: *mut TF_Buffer,
                         status: *mut TF_Status);
    pub fn TF_SessionPRunSetup(session: *mut TF_Session,
                               inputs: *const TF_Output,
                               ninputs: c_int,
                               outputs: *const TF_Output,
                               noutputs: c_int,
                               target_operations: *const *const TF_Operation,
                               ntargets: c_int,
                               handle: *const *const c_char,
                               status: *mut TF_Status);
    pub fn TF_SessionPRun(session: *mut TF_Session,
                          handle: *const c_char,
                          inputs: *const TF_Output,
                          input_values: *const *mut TF_Tensor,
                          ninputs: c_int,
                          outputs: *const TF_Output,
                          output_values: *mut *mut TF_Tensor,
                          noutputs: c_int,
                          target_operations: *const *const TF_Operation,
                          ntargets: c_int,
                          status: *mut TF_Status);
    pub fn TF_Version() -> *const c_char;
    pub fn TF_StringEncode(src: *const c_char,
                           src_len: size_t,
                           dst: *mut c_char,
                           dst_len: size_t,
                           status: *mut TF_Status)
                           -> size_t;
    pub fn TF_StringDecode(src: *const c_char,
                           src_len: size_t,
                           dst: *mut *const c_char,
                           dst_len: *mut size_t,
                           status: *mut TF_Status)
                           -> size_t;
    pub fn TF_StringEncodedSize(len: size_t) -> size_t;
}

#[deprecated(note="Use TF_SetAttrValueProto instead.")]
#[allow(non_snake_case)]
pub unsafe extern "C" fn TF_SetAttrToAttrValueProto(desc: *mut TF_OperationDescription,
                                                    attr_name: *const c_char,
                                                    proto: *const c_void,
                                                    proto_len: size_t,
                                                    status: *mut TF_Status) {
    TF_SetAttrValueProto(desc, attr_name, proto, proto_len, status)
}
<commit_msg>Replace hand-written lib.rs with an `include!()` of bindgen.rs<commit_after>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

include!("bindgen.rs");

pub use TF_Code::*;
pub use TF_DataType::*;
pub use TF_AttrType::*;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use super::super::{strfmt, Fmt};

#[test]
fn test_values() {
    let mut vars: HashMap<String, String> = HashMap::new();
    let too_long = "toooloooong".to_string();
    vars.insert("x".to_string(), "X".to_string());
    vars.insert("long".to_string(), too_long.clone());  // len=10
    vars.insert("hi".to_string(), "hi".to_string());

    // format, expected, error
    let values = vec![
        // simple positioning
        ("{x}", "X", false),
        ("{x:}", "X", false),
        ("{x:3}", "  X", false),
        ("{x:>3}", "  X", false),
        ("{x:<3}", "X  ", false),
        ("{x:^3}", " X ", false),
        ("{x:^4}", " X  ", false),

        // extra text
        (" {x}yz", " Xyz", false),
        (" hi {x:^4}-you rock", " hi  X  -you rock", false),

        // fill confusion
        ("{x:10}", "         X", false),
        ("{long:.3}", "too", false),
        ("{long:<5.3}", "too  ", false),
        ("{long:5.3}", "  too", false),
        ("{long:5.7}", "toooloo", false),
        ("{long:<5.7}", "toooloo", false),
        ("{long:^5.7}", "toooloo", false),
        ("{long:<}", &too_long, false),
        ("{long:<<}", &too_long, false),
        ("{long:<<5}", &too_long, false),

        // fun
        ("{x:<>}", "X", false),
        ("{x:<>3}", "<<X", false),
        ("{{}}", "{{}}", false),
        ("{{{x}}}", "{{X}}", false),
        ("{{{x}{{{{{{", "{{X{{{{{{", false),
        ("{x}}}}", "X}}}", false),

        // invalid
        ("{}", "", true),
        ("{:3}", "", true),
        ("{x:*}", "", true),
        ("{x::}", "", true),
        ("{x:<<<}", "", true),
        ("{xxx:  <88.3}", "", true),
    ];

    for (fmtstr, expected, expect_err) in values {
        let result = strfmt(fmtstr, &vars);
        let mut err = expect_err != result.is_err();
        if !err && !expect_err {
            err = match &result {
                &Ok(ref r) => r != expected,
                _ => unreachable!(),
            };
        }

        if err {
            let ex_type = if expect_err {
                "fail"
            } else {
                "pass"
            };
            let fmt = Fmt::from_str(fmtstr);
            println!("FAIL: expected {}", ex_type);
            println!("    input: {:?}", (fmtstr, expected, expect_err));
            println!("    fmt: {:?}", fmt);
            if !expect_err {
                          println!("    expected: {:?}", expected);
            }
            match result {
                Ok(v) =>  println!("         got: {:?}", v),
                Err(v) => println!("         got: {:?}", v),
            }
            assert!(false);
        }
    }
}

// #[bench]
// fn bench_strfmt(b: &mut Bencher) {
//     let mut vars: HashMap<String, String> = HashMap::new();
//     let too_long = "toooloooong".to_string();
//     vars.insert("x".to_string(), "X".to_string());
//     let fmtstr = "short: {x:*^10.3} long: {long:%<14.9}";
//     b.iter(|| strfmt(fmtstr, &vars));
// }

<commit_msg>Added test cases<commit_after>use std::collections::HashMap;
use super::super::{strfmt, Fmt};

#[test]
fn test_values() {
    let mut vars: HashMap<String, String> = HashMap::new();
    let too_long = "toooloooong".to_string();
    vars.insert("x".to_string(), "X".to_string());
    vars.insert("long".to_string(), too_long.clone());  // len=10
    vars.insert("hi".to_string(), "hi".to_string());

    // format, expected, error
    let values = vec![
        // simple positioning
        ("{x}", "X", false),
        ("{x:}", "X", false),
        ("{x:3}", "  X", false),
        ("{x:>3}", "  X", false),
        ("{x:<3}", "X  ", false),
        ("{x:^3}", " X ", false),
        ("{x:^4}", " X  ", false),

        // extra text
        (" {x}yz", " Xyz", false),
        (" hi {x:^4}-you rock", " hi  X  -you rock", false),

        // fill confusion
        ("{x:10}", "         X", false),
        ("{long:.3}", "too", false),
        ("{long:<5.3}", "too  ", false),
        ("{long:5.3}", "  too", false),
        ("{long:5.7}", "toooloo", false),
        ("{long:<5.7}", "toooloo", false),
        ("{long:^5.7}", "toooloo", false),
        ("{long:<}", &too_long, false),
        ("{long:<<}", &too_long, false),
        ("{long:<<5}", &too_long, false),

        // fun
        ("{x:<>}", "X", false),
        ("{x:<>3}", "<<X", false),
        ("{{}}", "{{}}", false),
        ("{{{x}}}", "{{X}}", false),
        ("{{{x}{{{{{{", "{{X{{{{{{", false),
        ("{x}}}}", "X}}}", false),

        // invalid
        ("{}", "", true),
        ("{:3}", "", true),
        ("{x:*}", "", true),
        ("{x::}", "", true),
        ("{x:<<<}", "", true),
        ("{xxx:  <88.3}", "", true),

        // escape
        ("{{}}", "{}", false),
        ("{{long}}", "{long}", false),
        ("{{{x}}}", "{X}", false),
    ];

    for (fmtstr, expected, expect_err) in values {
        let result = strfmt(fmtstr, &vars);
        let mut err = expect_err != result.is_err();
        if !err && !expect_err {
            err = match &result {
                &Ok(ref r) => r != expected,
                _ => unreachable!(),
            };
        }

        if err {
            let ex_type = if expect_err {
                "fail"
            } else {
                "pass"
            };
            let fmt = Fmt::from_str(fmtstr);
            println!("FAIL: expected {}", ex_type);
            println!("    input: {:?}", (fmtstr, expected, expect_err));
            println!("    fmt: {:?}", fmt);
            if !expect_err {
                          println!("    expected: {:?}", expected);
            }
            match result {
                Ok(v) =>  println!("         got: {:?}", v),
                Err(v) => println!("         got: {:?}", v),
            }
            assert!(false);
        }
    }
}

// #[bench]
// fn bench_strfmt(b: &mut Bencher) {
//     let mut vars: HashMap<String, String> = HashMap::new();
//     let too_long = "toooloooong".to_string();
//     vars.insert("x".to_string(), "X".to_string());
//     let fmtstr = "short: {x:*^10.3} long: {long:%<14.9}";
//     b.iter(|| strfmt(fmtstr, &vars));
// }

<|endoftext|>


<commit_before>use crate::TextRange;

use ra_syntax::ast::PatKind;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
    AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent,
};

#[derive(Debug, Clone)]
pub struct StructureNode {
    pub parent: Option<usize>,
    pub label: String,
    pub navigation_range: TextRange,
    pub node_range: TextRange,
    pub kind: SyntaxKind,
    pub detail: Option<String>,
    pub deprecated: bool,
}

pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
    let mut res = Vec::new();
    let mut stack = Vec::new();

    for event in file.syntax().preorder() {
        match event {
            WalkEvent::Enter(node) => {
                if let Some(mut symbol) = structure_node(&node) {
                    symbol.parent = stack.last().copied();
                    stack.push(res.len());
                    res.push(symbol);
                }
            }
            WalkEvent::Leave(node) => {
                if structure_node(&node).is_some() {
                    stack.pop().unwrap();
                }
            }
        }
    }
    res
}

fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
    fn decl<N: NameOwner + AttrsOwner>(node: N) -> Option<StructureNode> {
        decl_with_detail(node, None)
    }

    fn decl_with_ascription<N: NameOwner + AttrsOwner + TypeAscriptionOwner>(
        node: N,
    ) -> Option<StructureNode> {
        let ty = node.ascribed_type();
        decl_with_type_ref(node, ty)
    }

    fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
        node: N,
        type_ref: Option<ast::TypeRef>,
    ) -> Option<StructureNode> {
        let detail = type_ref.map(|type_ref| {
            let mut detail = String::new();
            collapse_ws(type_ref.syntax(), &mut detail);
            detail
        });
        decl_with_detail(node, detail)
    }

    fn decl_with_detail<N: NameOwner + AttrsOwner>(
        node: N,
        detail: Option<String>,
    ) -> Option<StructureNode> {
        let name = node.name()?;

        Some(StructureNode {
            parent: None,
            label: name.text().to_string(),
            navigation_range: name.syntax().text_range(),
            node_range: node.syntax().text_range(),
            kind: node.syntax().kind(),
            detail,
            deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"),
        })
    }

    fn collapse_ws(node: &SyntaxNode, output: &mut String) {
        let mut can_insert_ws = false;
        node.text().for_each_chunk(|chunk| {
            for line in chunk.lines() {
                let line = line.trim();
                if line.is_empty() {
                    if can_insert_ws {
                        output.push(' ');
                        can_insert_ws = false;
                    }
                } else {
                    output.push_str(line);
                    can_insert_ws = true;
                }
            }
        })
    }

    visitor()
        .visit(|fn_def: ast::FnDef| {
            let mut detail = String::from("fn");
            if let Some(type_param_list) = fn_def.type_param_list() {
                collapse_ws(type_param_list.syntax(), &mut detail);
            }
            if let Some(param_list) = fn_def.param_list() {
                collapse_ws(param_list.syntax(), &mut detail);
            }
            if let Some(ret_type) = fn_def.ret_type() {
                detail.push_str(" ");
                collapse_ws(ret_type.syntax(), &mut detail);
            }

            decl_with_detail(fn_def, Some(detail))
        })
        .visit(decl::<ast::StructDef>)
        .visit(decl::<ast::EnumDef>)
        .visit(decl::<ast::EnumVariant>)
        .visit(decl::<ast::TraitDef>)
        .visit(decl::<ast::Module>)
        .visit(|td: ast::TypeAliasDef| {
            let ty = td.type_ref();
            decl_with_type_ref(td, ty)
        })
        .visit(decl_with_ascription::<ast::NamedFieldDef>)
        .visit(decl_with_ascription::<ast::ConstDef>)
        .visit(decl_with_ascription::<ast::StaticDef>)
        .visit(|im: ast::ImplBlock| {
            let target_type = im.target_type()?;
            let target_trait = im.target_trait();
            let label = match target_trait {
                None => format!("impl {}", target_type.syntax().text()),
                Some(t) => {
                    format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
                }
            };

            let node = StructureNode {
                parent: None,
                label,
                navigation_range: target_type.syntax().text_range(),
                node_range: im.syntax().text_range(),
                kind: im.syntax().kind(),
                detail: None,
                deprecated: false,
            };
            Some(node)
        })
        .visit(|mc: ast::MacroCall| {
            let first_token = mc.syntax().first_token().unwrap();
            if first_token.text().as_str() != "macro_rules" {
                return None;
            }
            decl(mc)
        })
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            let mut label = String::new();
            collapse_ws(let_syntax, &mut label);

            let pat = match let_statement.pat()?.kind() {
                PatKind::BindPat(bind_pat) => bind_pat,
                _ => return None,
            };

            Some(StructureNode {
                parent: None,
                label,
                navigation_range: pat.syntax().range(),
                node_range: let_syntax.range(),
                kind: let_syntax.kind(),
                detail: None,
                deprecated: false,
            })
        })
        .accept(&node)?
}

#[cfg(test)]
mod tests {
    use super::*;
    use insta::assert_debug_snapshot_matches;

    #[test]
    fn test_file_structure() {
        let file = SourceFile::parse(
            r#"
struct Foo {
    x: i32
}

mod m {
    fn bar1() {}
    fn bar2<T>(t: T) -> T {}
    fn bar3<A,
        B>(a: A,
        b: B) -> Vec<
        u32
    > {}
}

enum E { X, Y(i32) }
type T = ();
static S: i32 = 92;
const C: i32 = 92;

impl E {}

impl fmt::Debug for E {}

macro_rules! mc {
    () => {}
}

#[deprecated]
fn obsolete() {}

#[deprecated(note = "for awhile")]
fn very_obsolete() {}
"#,
        )
        .ok()
        .unwrap();
        let structure = file_structure(&file);
        assert_debug_snapshot_matches!("file_structure", structure);
    }
}
<commit_msg>Do not show a lens when the type is declared explicitly<commit_after>use crate::TextRange;

use ra_syntax::ast::PatKind;
use ra_syntax::{
    algo::visit::{visitor, Visitor},
    ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
    AstNode, SourceFile, SyntaxKind, SyntaxNode, WalkEvent,
};

#[derive(Debug, Clone)]
pub struct StructureNode {
    pub parent: Option<usize>,
    pub label: String,
    pub navigation_range: TextRange,
    pub node_range: TextRange,
    pub kind: SyntaxKind,
    pub detail: Option<String>,
    pub deprecated: bool,
}

pub fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
    let mut res = Vec::new();
    let mut stack = Vec::new();

    for event in file.syntax().preorder() {
        match event {
            WalkEvent::Enter(node) => {
                if let Some(mut symbol) = structure_node(&node) {
                    symbol.parent = stack.last().copied();
                    stack.push(res.len());
                    res.push(symbol);
                }
            }
            WalkEvent::Leave(node) => {
                if structure_node(&node).is_some() {
                    stack.pop().unwrap();
                }
            }
        }
    }
    res
}

fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
    fn decl<N: NameOwner + AttrsOwner>(node: N) -> Option<StructureNode> {
        decl_with_detail(node, None)
    }

    fn decl_with_ascription<N: NameOwner + AttrsOwner + TypeAscriptionOwner>(
        node: N,
    ) -> Option<StructureNode> {
        let ty = node.ascribed_type();
        decl_with_type_ref(node, ty)
    }

    fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
        node: N,
        type_ref: Option<ast::TypeRef>,
    ) -> Option<StructureNode> {
        let detail = type_ref.map(|type_ref| {
            let mut detail = String::new();
            collapse_ws(type_ref.syntax(), &mut detail);
            detail
        });
        decl_with_detail(node, detail)
    }

    fn decl_with_detail<N: NameOwner + AttrsOwner>(
        node: N,
        detail: Option<String>,
    ) -> Option<StructureNode> {
        let name = node.name()?;

        Some(StructureNode {
            parent: None,
            label: name.text().to_string(),
            navigation_range: name.syntax().text_range(),
            node_range: node.syntax().text_range(),
            kind: node.syntax().kind(),
            detail,
            deprecated: node.attrs().filter_map(|x| x.as_named()).any(|x| x == "deprecated"),
        })
    }

    fn collapse_ws(node: &SyntaxNode, output: &mut String) {
        let mut can_insert_ws = false;
        node.text().for_each_chunk(|chunk| {
            for line in chunk.lines() {
                let line = line.trim();
                if line.is_empty() {
                    if can_insert_ws {
                        output.push(' ');
                        can_insert_ws = false;
                    }
                } else {
                    output.push_str(line);
                    can_insert_ws = true;
                }
            }
        })
    }

    visitor()
        .visit(|fn_def: ast::FnDef| {
            let mut detail = String::from("fn");
            if let Some(type_param_list) = fn_def.type_param_list() {
                collapse_ws(type_param_list.syntax(), &mut detail);
            }
            if let Some(param_list) = fn_def.param_list() {
                collapse_ws(param_list.syntax(), &mut detail);
            }
            if let Some(ret_type) = fn_def.ret_type() {
                detail.push_str(" ");
                collapse_ws(ret_type.syntax(), &mut detail);
            }

            decl_with_detail(fn_def, Some(detail))
        })
        .visit(decl::<ast::StructDef>)
        .visit(decl::<ast::EnumDef>)
        .visit(decl::<ast::EnumVariant>)
        .visit(decl::<ast::TraitDef>)
        .visit(decl::<ast::Module>)
        .visit(|td: ast::TypeAliasDef| {
            let ty = td.type_ref();
            decl_with_type_ref(td, ty)
        })
        .visit(decl_with_ascription::<ast::NamedFieldDef>)
        .visit(decl_with_ascription::<ast::ConstDef>)
        .visit(decl_with_ascription::<ast::StaticDef>)
        .visit(|im: ast::ImplBlock| {
            let target_type = im.target_type()?;
            let target_trait = im.target_trait();
            let label = match target_trait {
                None => format!("impl {}", target_type.syntax().text()),
                Some(t) => {
                    format!("impl {} for {}", t.syntax().text(), target_type.syntax().text(),)
                }
            };

            let node = StructureNode {
                parent: None,
                label,
                navigation_range: target_type.syntax().text_range(),
                node_range: im.syntax().text_range(),
                kind: im.syntax().kind(),
                detail: None,
                deprecated: false,
            };
            Some(node)
        })
        .visit(|mc: ast::MacroCall| {
            let first_token = mc.syntax().first_token().unwrap();
            if first_token.text().as_str() != "macro_rules" {
                return None;
            }
            decl(mc)
        })
        .visit(|let_statement: ast::LetStmt| {
            let let_syntax = let_statement.syntax();

            let mut label = String::new();
            collapse_ws(let_syntax, &mut label);

            if let_statement.ascribed_type().is_some() {
                return None;
            }

            let pat = match let_statement.pat()?.kind() {
                PatKind::BindPat(bind_pat) => bind_pat,
                _ => return None,
            };

            Some(StructureNode {
                parent: None,
                label,
                navigation_range: pat.syntax().range(),
                node_range: let_syntax.range(),
                kind: let_syntax.kind(),
                detail: None,
                deprecated: false,
            })
        })
        .accept(&node)?
}

#[cfg(test)]
mod tests {
    use super::*;
    use insta::assert_debug_snapshot_matches;

    #[test]
    fn test_file_structure() {
        let file = SourceFile::parse(
            r#"
struct Foo {
    x: i32
}

mod m {
    fn bar1() {}
    fn bar2<T>(t: T) -> T {}
    fn bar3<A,
        B>(a: A,
        b: B) -> Vec<
        u32
    > {}
}

enum E { X, Y(i32) }
type T = ();
static S: i32 = 92;
const C: i32 = 92;

impl E {}

impl fmt::Debug for E {}

macro_rules! mc {
    () => {}
}

#[deprecated]
fn obsolete() {}

#[deprecated(note = "for awhile")]
fn very_obsolete() {}
"#,
        )
        .ok()
        .unwrap();
        let structure = file_structure(&file);
        assert_debug_snapshot_matches!("file_structure", structure);
    }
}
<|endoftext|>


<commit_before>//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction.
//!
//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use
//! privileged system registers from userspace to check CPU feature support.
//!
//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1
//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc.
//! Each part of the register indicates the level of support for a certain feature, e.g.
//! when ID_AA64ISAR0_EL1\[7:4\] is >= 1, AES is supported; when it's >= 2, PMULL is supported.
//!
//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb),
//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947).
//!
//! References:
//!
//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp)
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)

use crate::detect::{cache, Feature};

/// Try to read the features from the system registers.
///
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
pub(crate) fn detect_features() -> cache::Initializer {
    let mut value = cache::Initializer::default();

    {
        let mut enable_feature = |f, enable| {
            if enable {
                value.set(f as u32);
            }
        };

        // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
        let aa64isar0: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64ISAR0_EL1",
                out(reg) aa64isar0,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        enable_feature(Feature::pmull, bits_shift(aa64isar0, 7, 4) >= 2);
        enable_feature(Feature::tme, bits_shift(aa64isar0, 27, 24) == 1);
        enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
        enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);

        // ID_AA64PFR0_EL1 - Processor Feature Register 0
        let aa64pfr0: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64PFR0_EL1",
                out(reg) aa64pfr0,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
        let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
        let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
        let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
        enable_feature(Feature::fp, fp);
        enable_feature(Feature::fp16, fphp);
        // SIMD support requires float support - if half-floats are
        // supported, it also requires half-float support:
        enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
        // SIMD extensions require SIMD support:
        enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 1);
        let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
        let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
        enable_feature(Feature::sha2, asimd && sha1 && sha2);
        enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
        enable_feature(
            Feature::dotprod,
            asimd && bits_shift(aa64isar0, 47, 44) >= 1,
        );
        enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);

        // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1
        let aa64isar1: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64ISAR1_EL1",
                out(reg) aa64isar1,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        // Check for either APA or API field
        enable_feature(Feature::paca, bits_shift(aa64isar1, 11, 4) >= 1);
        enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
        // Check for either GPA or GPI field
        enable_feature(Feature::pacg, bits_shift(aa64isar1, 31, 24) >= 1);
    }

    value
}

#[inline]
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
    (x >> low) & ((1 << (high - low + 1)) - 1)
}
<commit_msg>Import the asm macro in std_detect (#1290)<commit_after>//! Run-time feature detection for Aarch64 on any OS that emulates the mrs instruction.
//!
//! On FreeBSD >= 12.0, Linux >= 4.11 and other operating systems, it is possible to use
//! privileged system registers from userspace to check CPU feature support.
//!
//! AArch64 system registers ID_AA64ISAR0_EL1, ID_AA64PFR0_EL1, ID_AA64ISAR1_EL1
//! have bits dedicated to features like AdvSIMD, CRC32, AES, atomics (LSE), etc.
//! Each part of the register indicates the level of support for a certain feature, e.g.
//! when ID_AA64ISAR0_EL1\[7:4\] is >= 1, AES is supported; when it's >= 2, PMULL is supported.
//!
//! For proper support of [SoCs where different cores have different capabilities](https://medium.com/@jadr2ddude/a-big-little-problem-a-tale-of-big-little-gone-wrong-e7778ce744bb),
//! the OS has to always report only the features supported by all cores, like [FreeBSD does](https://reviews.freebsd.org/D17137#393947).
//!
//! References:
//!
//! - [Zircon implementation](https://fuchsia.googlesource.com/zircon/+/master/kernel/arch/arm64/feature.cpp)
//! - [Linux documentation](https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt)

use crate::detect::{cache, Feature};
use core::arch::asm;

/// Try to read the features from the system registers.
///
/// This will cause SIGILL if the current OS is not trapping the mrs instruction.
pub(crate) fn detect_features() -> cache::Initializer {
    let mut value = cache::Initializer::default();

    {
        let mut enable_feature = |f, enable| {
            if enable {
                value.set(f as u32);
            }
        };

        // ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
        let aa64isar0: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64ISAR0_EL1",
                out(reg) aa64isar0,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        enable_feature(Feature::pmull, bits_shift(aa64isar0, 7, 4) >= 2);
        enable_feature(Feature::tme, bits_shift(aa64isar0, 27, 24) == 1);
        enable_feature(Feature::lse, bits_shift(aa64isar0, 23, 20) >= 1);
        enable_feature(Feature::crc, bits_shift(aa64isar0, 19, 16) >= 1);

        // ID_AA64PFR0_EL1 - Processor Feature Register 0
        let aa64pfr0: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64PFR0_EL1",
                out(reg) aa64pfr0,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        let fp = bits_shift(aa64pfr0, 19, 16) < 0xF;
        let fphp = bits_shift(aa64pfr0, 19, 16) >= 1;
        let asimd = bits_shift(aa64pfr0, 23, 20) < 0xF;
        let asimdhp = bits_shift(aa64pfr0, 23, 20) >= 1;
        enable_feature(Feature::fp, fp);
        enable_feature(Feature::fp16, fphp);
        // SIMD support requires float support - if half-floats are
        // supported, it also requires half-float support:
        enable_feature(Feature::asimd, fp && asimd && (!fphp | asimdhp));
        // SIMD extensions require SIMD support:
        enable_feature(Feature::aes, asimd && bits_shift(aa64isar0, 7, 4) >= 1);
        let sha1 = bits_shift(aa64isar0, 11, 8) >= 1;
        let sha2 = bits_shift(aa64isar0, 15, 12) >= 1;
        enable_feature(Feature::sha2, asimd && sha1 && sha2);
        enable_feature(Feature::rdm, asimd && bits_shift(aa64isar0, 31, 28) >= 1);
        enable_feature(
            Feature::dotprod,
            asimd && bits_shift(aa64isar0, 47, 44) >= 1,
        );
        enable_feature(Feature::sve, asimd && bits_shift(aa64pfr0, 35, 32) >= 1);

        // ID_AA64ISAR1_EL1 - Instruction Set Attribute Register 1
        let aa64isar1: u64;
        unsafe {
            asm!(
                "mrs {}, ID_AA64ISAR1_EL1",
                out(reg) aa64isar1,
                options(pure, nomem, preserves_flags, nostack)
            );
        }

        // Check for either APA or API field
        enable_feature(Feature::paca, bits_shift(aa64isar1, 11, 4) >= 1);
        enable_feature(Feature::rcpc, bits_shift(aa64isar1, 23, 20) >= 1);
        // Check for either GPA or GPI field
        enable_feature(Feature::pacg, bits_shift(aa64isar1, 31, 24) >= 1);
    }

    value
}

#[inline]
fn bits_shift(x: u64, high: usize, low: usize) -> u64 {
    (x >> low) & ((1 << (high - low + 1)) - 1)
}
<|endoftext|>


<commit_before>// Originally from https://github.com/rust-lang/crates.io/blob/master/src/s3/lib.rs
//#![deny(warnings)]

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;
use std::fmt;

use base64;
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;
use futures::{Future, Stream};
use hyper::{self, header};
use hyper::Method;
use hyper::client::{Client, Request, HttpConnector};
use hyper_tls::HttpsConnector;
use simples3::credential::*;
use time;
use tokio_core::reactor::Handle;

use errors::*;

#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
/// Whether or not to use SSL.
pub enum Ssl {
    /// Use SSL.
    Yes,
    /// Do not use SSL.
    No,
}

fn base_url(endpoint: &str, ssl: Ssl) -> String {
    format!("{}://{}/",
            match ssl {
                Ssl::Yes => "https",
                Ssl::No => "http",
            },
            endpoint)
}

fn hmac<D: Digest>(d: D, key: &[u8], data: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(d, key);
    hmac.input(data);
    hmac.result().code().iter().map(|b| *b).collect::<Vec<u8>>()
}

fn signature(string_to_sign: &str, signing_key: &str) -> String {
    let s = hmac(Sha1::new(), signing_key.as_bytes(), string_to_sign.as_bytes());
    base64::encode_config::<Vec<u8>>(&s, base64::STANDARD)
}

/// An S3 bucket.
pub struct Bucket {
    name: String,
    base_url: String,
    client: Client<HttpsConnector<HttpConnector>>,
}

impl fmt::Display for Bucket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Bucket(name={}, base_url={})", self.name, self.base_url)
    }
}

impl Bucket {
    pub fn new(name: &str, endpoint: &str, ssl: Ssl, handle: &Handle)
        -> Result<Bucket>
    {
        let base_url = base_url(&endpoint, ssl);
        Ok(Bucket {
            name: name.to_owned(),
            base_url: base_url,
            client: Client::configure()
                        .connector(HttpsConnector::new(1, handle)?)
                        .build(handle),
        })
    }

    pub fn get(&self, key: &str) -> SFuture<Vec<u8>> {
        let url = format!("{}{}", self.base_url, key);
        debug!("GET {}", url);
        let url2 = url.clone();
        Box::new(self.client.get(url.parse().unwrap()).chain_err(move || {
            format!("failed GET: {}", url)
        }).and_then(|res| {
            if res.status().is_success() {
                let content_length = res.headers().get::<header::ContentLength>()
                    .map(|&header::ContentLength(len)| len);
                Ok((res.body(), content_length))
            } else {
                Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
            }
        }).and_then(|(body, content_length)| {
            body.fold(Vec::new(), |mut body, chunk| {
                body.extend_from_slice(&chunk);
                Ok::<_, hyper::Error>(body)
            }).chain_err(|| {
                "failed to read HTTP body"
            }).and_then(move |bytes| {
                if let Some(len) = content_length {
                    if len != bytes.len() as u64 {
                        bail!(format!("Bad HTTP body size read: {}, expected {}", bytes.len(), len));
                    } else {
                        info!("Read {} bytes from {}", bytes.len(), url2);
                    }
                }
                Ok(bytes)
            })
        }))
    }

    pub fn put(&self, key: &str, content: Vec<u8>, creds: &AwsCredentials)
               -> SFuture<()> {
        let url = format!("{}{}", self.base_url, key);
        debug!("PUT {}", url);
        let mut request = Request::new(Method::Put, url.parse().unwrap());

        let content_type = "application/octet-stream";
        let date = time::now_utc().rfc822().to_string();
        let mut canonical_headers = String::new();
        let token = creds.token().as_ref().map(|s| s.as_str());
        // Keep the list of header values sorted!
        for (header, maybe_value) in vec![
            ("x-amz-security-token", token),
            ] {
            if let Some(ref value) = maybe_value {
                request.headers_mut()
                       .set_raw(header, vec!(value.as_bytes().to_vec()));
                canonical_headers.push_str(format!("{}:{}\n", header.to_ascii_lowercase(), value).as_ref());
            }
        }
        let auth = self.auth("PUT", &date, key, "", &canonical_headers, content_type, creds);
        request.headers_mut().set_raw("Date", vec!(date.into_bytes()));
        request.headers_mut().set(header::ContentType(content_type.parse().unwrap()));
        request.headers_mut().set(header::ContentLength(content.len() as u64));
        request.headers_mut().set(header::CacheControl(vec![
            // Two weeks
            header::CacheDirective::MaxAge(1296000)
        ]));
        request.headers_mut().set_raw("Authorization", vec!(auth.into_bytes()));
        request.set_body(content);

        Box::new(self.client.request(request).then(|result| {
            match result {
                Ok(res) => {
                    if res.status().is_success() {
                        trace!("PUT succeeded");
                        Ok(())
                    } else {
                        trace!("PUT failed with HTTP status: {}", res.status());
                        Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
                    }
                }
                Err(e) => {
                    trace!("PUT failed with error: {:?}", e);
                    Err(e.into())
                }
            }
        }))
    }

    // http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
    fn auth(&self, verb: &str, date: &str, path: &str,
            md5: &str, headers: &str, content_type: &str, creds: &AwsCredentials) -> String {
        let string = format!("{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
                             verb = verb,
                             md5 = md5,
                             ty = content_type,
                             date = date,
                             headers = headers,
                             resource = format!("/{}/{}", self.name, path));
        let signature = signature(&string, creds.aws_secret_access_key());
        format!("AWS {}:{}", creds.aws_access_key_id(), signature)
    }
}
<commit_msg>Use Reqwest to access s3 to follow redirects<commit_after>// Originally from https://github.com/rust-lang/crates.io/blob/master/src/s3/lib.rs
//#![deny(warnings)]

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;
use std::fmt;

use base64;
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;
use futures::{Future, Stream};
use hyper::header;
use hyper::Method;
use reqwest;
use reqwest::unstable::async::{Client, Request};
use simples3::credential::*;
use time;
use tokio_core::reactor::Handle;

use errors::*;

#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
/// Whether or not to use SSL.
pub enum Ssl {
    /// Use SSL.
    Yes,
    /// Do not use SSL.
    No,
}

fn base_url(endpoint: &str, ssl: Ssl) -> String {
    format!(
        "{}://{}/",
        match ssl {
            Ssl::Yes => "https",
            Ssl::No => "http",
        },
        endpoint
    )
}

fn hmac<D: Digest>(d: D, key: &[u8], data: &[u8]) -> Vec<u8> {
    let mut hmac = Hmac::new(d, key);
    hmac.input(data);
    hmac.result().code().iter().map(|b| *b).collect::<Vec<u8>>()
}

fn signature(string_to_sign: &str, signing_key: &str) -> String {
    let s = hmac(
        Sha1::new(),
        signing_key.as_bytes(),
        string_to_sign.as_bytes(),
    );
    base64::encode_config::<Vec<u8>>(&s, base64::STANDARD)
}

/// An S3 bucket.
pub struct Bucket {
    name: String,
    base_url: String,
    client: Client,
}

impl fmt::Display for Bucket {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Bucket(name={}, base_url={})", self.name, self.base_url)
    }
}

impl Bucket {
    pub fn new(name: &str, endpoint: &str, ssl: Ssl, handle: &Handle) -> Result<Bucket> {
        let base_url = base_url(&endpoint, ssl);
        Ok(Bucket {
            name: name.to_owned(),
            base_url: base_url,
            client: Client::new(handle),
        })
    }

    pub fn get(&self, key: &str) -> SFuture<Vec<u8>> {
        let url = format!("{}{}", self.base_url, key);
        debug!("GET {}", url);
        let url2 = url.clone();
        Box::new(
            self.client
                .get(&url[..])
                .send()
                .chain_err(move || format!("failed GET: {}", url))
                .and_then(|res| {
                    if res.status().is_success() {
                        let content_length = res
                            .headers()
                            .get::<header::ContentLength>()
                            .map(|&header::ContentLength(len)| len);
                        Ok((res.into_body(), content_length))
                    } else {
                        Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
                    }
                })
                .and_then(|(body, content_length)| {
                    body.fold(Vec::new(), |mut body, chunk| {
                        body.extend_from_slice(&chunk);
                        Ok::<_, reqwest::Error>(body)
                    }).chain_err(|| "failed to read HTTP body")
                        .and_then(move |bytes| {
                            if let Some(len) = content_length {
                                if len != bytes.len() as u64 {
                                    bail!(format!(
                                        "Bad HTTP body size read: {}, expected {}",
                                        bytes.len(),
                                        len
                                    ));
                                } else {
                                    info!("Read {} bytes from {}", bytes.len(), url2);
                                }
                            }
                            Ok(bytes)
                        })
                }),
        )
    }

    pub fn put(&self, key: &str, content: Vec<u8>, creds: &AwsCredentials) -> SFuture<()> {
        let url = format!("{}{}", self.base_url, key);
        debug!("PUT {}", url);
        let mut request = Request::new(Method::Put, url.parse().unwrap());

        let content_type = "application/octet-stream";
        let date = time::now_utc().rfc822().to_string();
        let mut canonical_headers = String::new();
        let token = creds.token().as_ref().map(|s| s.as_str());
        // Keep the list of header values sorted!
        for (header, maybe_value) in vec![("x-amz-security-token", token)] {
            if let Some(ref value) = maybe_value {
                request
                    .headers_mut()
                    .set_raw(header, vec![value.as_bytes().to_vec()]);
                canonical_headers
                    .push_str(format!("{}:{}\n", header.to_ascii_lowercase(), value).as_ref());
            }
        }
        let auth = self.auth(
            "PUT",
            &date,
            key,
            "",
            &canonical_headers,
            content_type,
            creds,
        );
        request
            .headers_mut()
            .set_raw("Date", vec![date.into_bytes()]);
        request
            .headers_mut()
            .set(header::ContentType(content_type.parse().unwrap()));
        request
            .headers_mut()
            .set(header::ContentLength(content.len() as u64));
        request.headers_mut().set(header::CacheControl(vec![
            // Two weeks
            header::CacheDirective::MaxAge(1296000),
        ]));
        request
            .headers_mut()
            .set_raw("Authorization", vec![auth.into_bytes()]);
        *request.body_mut() = Some(content.into());

        Box::new(self.client.execute(request).then(|result| match result {
            Ok(res) => {
                if res.status().is_success() {
                    trace!("PUT succeeded");
                    Ok(())
                } else {
                    trace!("PUT failed with HTTP status: {}", res.status());
                    Err(ErrorKind::BadHTTPStatus(res.status().clone()).into())
                }
            }
            Err(e) => {
                trace!("PUT failed with error: {:?}", e);
                Err(e.into())
            }
        }))
    }

    // http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
    fn auth(
        &self,
        verb: &str,
        date: &str,
        path: &str,
        md5: &str,
        headers: &str,
        content_type: &str,
        creds: &AwsCredentials,
    ) -> String {
        let string = format!(
            "{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
            verb = verb,
            md5 = md5,
            ty = content_type,
            date = date,
            headers = headers,
            resource = format!("/{}/{}", self.name, path)
        );
        let signature = signature(&string, creds.aws_secret_access_key());
        format!("AWS {}:{}", creds.aws_access_key_id(), signature)
    }
}
<|endoftext|>


<commit_before>use time;
use hash::SubotaiHash;
use std::collections::HashMap;
use std::sync::RwLock;

pub const MAX_STORAGE: usize = 10000;

/// Distance after which the expiration time for a particular key will begin
/// to drop dramatically. Prevents over-caching.
const BASE_EXPIRATION_TIME_HRS : i64 = 24;
const EXPIRATION_DISTANCE_THRESHOLD : usize = 5;

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum StorageEntry {
   Value(SubotaiHash),
   Blob(Vec<u8>),
}

#[derive(Debug, Clone)]
struct EntryAndExpiration {
   entry      : StorageEntry,
   expiration : time::SteadyTime,
}

pub struct Storage {
   entries_and_expirations : RwLock<HashMap<SubotaiHash, EntryAndExpiration> >,
   parent_id               : SubotaiHash,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum StoreResult {
   Success,
   AlreadyPresent,
   StorageFull,
}

impl Storage {
   pub fn new(parent_id: SubotaiHash) -> Storage {
      Storage {
         entries_and_expirations : RwLock::new(HashMap::with_capacity(MAX_STORAGE)),
         parent_id               : parent_id,
      }
   }

   pub fn len(&self) -> usize {
      self.entries_and_expirations.read().unwrap().len()
   }

   pub fn is_empty(&self) -> bool {
      self.entries_and_expirations.read().unwrap().is_empty()
   }

   pub fn store(&self, key: SubotaiHash, entry: StorageEntry) -> StoreResult {
      let mut entries_and_expirations = self.entries_and_expirations.write().unwrap();
      let expiration = time::SteadyTime::now() + time::Duration::hours(BASE_EXPIRATION_TIME_HRS);

      let entry_and_expiration = EntryAndExpiration { entry: entry, expiration: expiration, };
      if entries_and_expirations.len() >= MAX_STORAGE {
         StoreResult::StorageFull
      } else {
         match entries_and_expirations.insert(key, entry_and_expiration) {
            None    => StoreResult::Success,
            Some(_) => StoreResult::AlreadyPresent,
         }
      }
   }

   pub fn get(&self, key: &SubotaiHash) -> Option<StorageEntry> {
      if let Some( &EntryAndExpiration { ref entry, .. } ) = self.entries_and_expirations.read().unwrap().get(key) {
         Some(entry.clone())
      } else {
         None
      }
   }
}

#[cfg(test)]
mod tests {
   use super::*;
   use storage;
   use hash;
   use time;

   #[test]
   fn expiration_date_calculation_below_distance_threshold() {
      let id = hash::SubotaiHash::random();
      let storage = Storage::new(id.clone());

      // We create a key at distance 1 from our node, and another at distance
      // `EXPIRATION_DISTANCE_FACTOR`
      let key_at_1 = hash::SubotaiHash::random_at_distance(&id, 1);
      let key_at_expf = hash::SubotaiHash::random_at_distance(&id, storage::EXPIRATION_DISTANCE_THRESHOLD);
      let dummy_entry = StorageEntry::Value(hash::SubotaiHash::random());

      storage.store(key_at_1.clone(), dummy_entry.clone());
      storage.store(key_at_expf.clone(), dummy_entry.clone());

      // Both keys should have an expiration date of roughly 24 hours from now.
      let exp_alpha = storage.entries_and_expirations.read().unwrap().get(&key_at_1).unwrap().expiration.clone();
      let exp_beta  = storage.entries_and_expirations.read().unwrap().get(&key_at_expf).unwrap().expiration.clone();

      let max_duration = time::Duration::hours(24);
      let min_duration = time::Duration::hours(23);

      assert!(exp_alpha <= time::SteadyTime::now() + max_duration);
      assert!(exp_alpha >= time::SteadyTime::now() + min_duration);
      assert!(exp_beta  <= time::SteadyTime::now() + max_duration);
      assert!(exp_beta  >= time::SteadyTime::now() + min_duration);
   }

}

<commit_msg>Expiration date calculation<commit_after>use time;
use hash::SubotaiHash;
use std::collections::HashMap;
use std::sync::RwLock;
use std::cmp;

pub const MAX_STORAGE: usize = 10000;

/// Distance after which the expiration time for a particular key will begin
/// to drop dramatically. Prevents over-caching.
const BASE_EXPIRATION_TIME_HRS : i64 = 24;
const EXPIRATION_DISTANCE_THRESHOLD : usize = 3;

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum StorageEntry {
   Value(SubotaiHash),
   Blob(Vec<u8>),
}

#[derive(Debug, Clone)]
struct EntryAndExpiration {
   entry      : StorageEntry,
   expiration : time::SteadyTime,
}

pub struct Storage {
   entries_and_expirations : RwLock<HashMap<SubotaiHash, EntryAndExpiration> >,
   parent_id               : SubotaiHash,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum StoreResult {
   Success,
   AlreadyPresent,
   StorageFull,
}

impl Storage {
   pub fn new(parent_id: SubotaiHash) -> Storage {
      Storage {
         entries_and_expirations : RwLock::new(HashMap::with_capacity(MAX_STORAGE)),
         parent_id               : parent_id,
      }
   }

   pub fn len(&self) -> usize {
      self.entries_and_expirations.read().unwrap().len()
   }

   pub fn is_empty(&self) -> bool {
      self.entries_and_expirations.read().unwrap().is_empty()
   }

   pub fn store(&self, key: SubotaiHash, entry: StorageEntry) -> StoreResult {
      let mut entries_and_expirations = self.entries_and_expirations.write().unwrap();
      let expiration = self.calculate_expiration_date(&key);

      let entry_and_expiration = EntryAndExpiration { entry: entry, expiration: expiration, };
      if entries_and_expirations.len() >= MAX_STORAGE {
         StoreResult::StorageFull
      } else {
         match entries_and_expirations.insert(key, entry_and_expiration) {
            None    => StoreResult::Success,
            Some(_) => StoreResult::AlreadyPresent,
         }
      }
   }

   pub fn get(&self, key: &SubotaiHash) -> Option<StorageEntry> {
      if let Some( &EntryAndExpiration { ref entry, .. } ) = self.entries_and_expirations.read().unwrap().get(key) {
         Some(entry.clone())
      } else {
         None
      }
   }

   /// the expiration time drops substantially the further away the parent node is from the key, past
   /// a threshold.
   fn calculate_expiration_date(&self, key: &SubotaiHash) -> time::SteadyTime {
      let distance = (&self.parent_id ^ &key).height().unwrap_or(0);
      let clamped_distance = cmp::max(1, cmp::min(16, distance));
      let expiration_factor = 2i64.pow(usize::saturating_sub(clamped_distance, EXPIRATION_DISTANCE_THRESHOLD) as u32);
      time::SteadyTime::now() + time::Duration::minutes(60 * BASE_EXPIRATION_TIME_HRS / expiration_factor)
   }
}

#[cfg(test)]
mod tests {
   use super::*;
   use {storage, hash, time};

   #[test]
   fn expiration_date_calculation_below_distance_threshold() {
      let id = hash::SubotaiHash::random();
      let storage = Storage::new(id.clone());

      // We create a key at distance 1 from our node, and another at distance
      // `EXPIRATION_DISTANCE_FACTOR`
      let key_at_1 = hash::SubotaiHash::random_at_distance(&id, 1);
      let key_at_expf = hash::SubotaiHash::random_at_distance(&id, storage::EXPIRATION_DISTANCE_THRESHOLD);
      let dummy_entry = StorageEntry::Value(hash::SubotaiHash::random());

      storage.store(key_at_1.clone(), dummy_entry.clone());
      storage.store(key_at_expf.clone(), dummy_entry.clone());

      // Both keys should have an expiration date of roughly 24 hours from now.
      let exp_alpha = storage.entries_and_expirations.read().unwrap().get(&key_at_1).unwrap().expiration.clone();
      let exp_beta  = storage.entries_and_expirations.read().unwrap().get(&key_at_expf).unwrap().expiration.clone();

      let max_duration = time::Duration::hours(storage::BASE_EXPIRATION_TIME_HRS);
      let min_duration = time::Duration::hours(storage::BASE_EXPIRATION_TIME_HRS) - time::Duration::minutes(1);

      assert!(exp_alpha <= time::SteadyTime::now() + max_duration);
      assert!(exp_alpha >= time::SteadyTime::now() + min_duration);
      assert!(exp_beta  <= time::SteadyTime::now() + max_duration);
      assert!(exp_beta  >= time::SteadyTime::now() + min_duration);
   }

   #[test]
   fn expiration_date_calculation_over_distance_threshold() {
      let id = hash::SubotaiHash::random();
      let storage = Storage::new(id.clone());

      // We create a key past the distance threshold;
      let excess = 2usize;
      let key = hash::SubotaiHash::random_at_distance(&id, storage::EXPIRATION_DISTANCE_THRESHOLD + excess);
      let dummy_entry = StorageEntry::Value(hash::SubotaiHash::random());
      storage.store(key.clone(), dummy_entry.clone());
      let expiration = storage.entries_and_expirations.read().unwrap().get(&key).unwrap().expiration.clone();

      let expiration_factor = 2i64.pow(excess as u32);
      let max_duration = time::Duration::minutes(60 * storage::BASE_EXPIRATION_TIME_HRS / expiration_factor );
      let min_duration = time::Duration::minutes(60 * storage::BASE_EXPIRATION_TIME_HRS / expiration_factor - 1);
      assert!(expiration <= time::SteadyTime::now() + max_duration);
      assert!(expiration >= time::SteadyTime::now() + min_duration);

   }

}

<|endoftext|>


<commit_before>//! A trivial global lock transaction system.
//!
//! At the moment, this is really just a global static mutex, that needs to be
//! locked, to ensure the atomicity of a transaction.

use std::sync::{StaticMutex, MUTEX_INIT};
use std::cell::RefCell;

/// The global transaction lock.
static TRANSACTION_MUTEX: StaticMutex = MUTEX_INIT;

/// Registry for callbacks to be executed at the end of a transaction.
thread_local!(
    static FINAL_CALLBACKS: RefCell<Vec<Box<Fn() + 'static>>>
        = RefCell::new(Vec::new())
);

/// Commit a transaction.
///
/// Acquires the global lock and then executes the closure.
pub fn commit<A, B, F: FnOnce(A) -> B>(args: A, transaction: F) -> B {
    // Acquire lock
    let _lock = TRANSACTION_MUTEX.lock().ok()
        .expect("global transaction mutex poisoned");
    // Make sure there are no stale callbacks
    FINAL_CALLBACKS.with(|store| {
        if store.borrow().len() > 0 {
            store.borrow_mut().clear();
        }
    });
    // Perform the transaction
    let result = transaction(args);
    // Call all finalizers
    FINAL_CALLBACKS.with(|store| {
        for callback in store.borrow_mut().drain() {
            callback();
        }
    });
    // Return
    result
}

/// Register a callback during a transaction.
pub fn register_callback<F: Fn() + 'static>(callback: F) {
    FINAL_CALLBACKS.with(move |store| {
        store.borrow_mut().push(Box::new(callback))
    });
}
<commit_msg>Fix for latest nightly<commit_after>//! A trivial global lock transaction system.
//!
//! At the moment, this is really just a global static mutex, that needs to be
//! locked, to ensure the atomicity of a transaction.

use std::sync::{StaticMutex, MUTEX_INIT};
use std::cell::RefCell;

/// The global transaction lock.
static TRANSACTION_MUTEX: StaticMutex = MUTEX_INIT;

/// Registry for callbacks to be executed at the end of a transaction.
thread_local!(
    static FINAL_CALLBACKS: RefCell<Vec<Box<Fn() + 'static>>>
        = RefCell::new(Vec::new())
);

/// Commit a transaction.
///
/// Acquires the global lock and then executes the closure.
pub fn commit<A, B, F: FnOnce(A) -> B>(args: A, transaction: F) -> B {
    // Acquire lock
    let _lock = TRANSACTION_MUTEX.lock().ok()
        .expect("global transaction mutex poisoned");
    // Make sure there are no stale callbacks
    FINAL_CALLBACKS.with(|store| {
        if store.borrow().len() > 0 {
            store.borrow_mut().clear();
        }
    });
    // Perform the transaction
    let result = transaction(args);
    // Call all finalizers
    FINAL_CALLBACKS.with(|store| {
        let mut store = store.borrow_mut();
        for callback in store.drain() {
            callback();
        }
    });
    // Return
    result
}

/// Register a callback during a transaction.
pub fn register_callback<F: Fn() + 'static>(callback: F) {
    FINAL_CALLBACKS.with(move |store| {
        store.borrow_mut().push(Box::new(callback))
    });
}
<|endoftext|>