use ::pipe::PipeDescriptor;
use ::pstd::{
pstd_type_accessor_t,
pstd_type_field_t,
pstd_type_model_t,
pstd_type_instance_t,
pstd_type_model_get_accessor,
pstd_type_model_get_field_info,
pstd_type_model_on_pipe_type_checked,
pstd_type_instance_read,
pstd_type_instance_write
};
use ::plumber_api_call::get_cstr;
use std::marker::PhantomData;
use std::collections::HashMap;
use std::rc::Rc;
pub struct TypeInstanceObject {
object: *mut pstd_type_instance_t
}
impl TypeInstanceObject {
pub fn from_raw(raw: *mut ::std::os::raw::c_void) -> Option<TypeInstanceObject>
{
if !raw.is_null()
{
return Some(TypeInstanceObject{
object : raw as *mut pstd_type_instance_t
});
}
return None;
}
fn read(&mut self,
acc:pstd_type_accessor_t,
buf:*mut ::std::os::raw::c_void,
size: usize) -> bool
{
let result = unsafe{ pstd_type_instance_read(self.object, acc, buf, size) };
return result == size;
}
fn write(&mut self,
acc:pstd_type_accessor_t,
buf:*const ::std::os::raw::c_void,
size:usize) -> bool
{
let result = unsafe{ pstd_type_instance_write(self.object, acc, buf, size) };
return result != -1;
}
}
pub type PrimitiveTypeShape = pstd_type_field_t;
impl Default for PrimitiveTypeShape {
fn default() -> PrimitiveTypeShape
{
return PrimitiveTypeShape {
offset:0,
size :0,
_bitfield_1: PrimitiveTypeShape::new_bitfield_1(0,0,0,0,0,0),
__bindgen_padding_0: [0;3usize]
};
}
}
pub struct TypeModelObject {
object : *mut pstd_type_model_t
}
struct TypeShapeChecker<'a , T : PrimitiveTypeTag<T> + Default> {
shape : &'a PrimitiveTypeShape,
phantom : PhantomData<T>
}
impl <'a, T:PrimitiveTypeTag<T> + Default> TypeShapeChecker<'a,T> {
fn do_check(&self) -> bool { return T::validate_type_shape(self.shape); }
}
impl TypeModelObject {
pub fn from_raw(raw : *mut ::std::os::raw::c_void) -> Option<TypeModelObject>
{
let inner_obj = raw;
if !inner_obj.is_null()
{
return Some(TypeModelObject {
object : inner_obj as *mut pstd_type_model_t
});
}
return None;
}
fn _add_type_shape_check<T>(&self,
pipe:PipeDescriptor,
path:*const ::std::os::raw::c_char,
primitive:&mut Primitive<T>) -> bool
where T : PrimitiveTypeTag<T> + Default
{
if -1 == unsafe {
pstd_type_model_get_field_info(self.object,
pipe,
path,
(&mut primitive.shape) as *mut PrimitiveTypeShape)
}
{
return false;
}
let check_shape = Box::new(TypeShapeChecker::<T>{
shape : &primitive.shape,
phantom: PhantomData
});
extern "C" fn _validate_primitive_type_shape<T>(_pipe: ::plumber_api::runtime_api_pipe_t,
data : *mut ::std::os::raw::c_void) -> i32
where T : PrimitiveTypeTag<T>+Default
{
let check_shape = unsafe{ Box::<TypeShapeChecker<T>>::from_raw(data as *mut TypeShapeChecker<T>) };
if check_shape.do_check()
{
return 0;
}
return -1;
}
let check_shape_ref = Box::leak(check_shape) as *mut TypeShapeChecker<T>;
unsafe{ pstd_type_model_on_pipe_type_checked(self.object,
pipe,
Some(_validate_primitive_type_shape::<T>),
check_shape_ref as *mut ::std::os::raw::c_void) };
return true;
}
pub fn assign_primitive<'a, 'b, T>(&self,
pipe:PipeDescriptor,
path:&'a str,
primitive:&'b mut Primitive<T>,
validate_type:bool) -> bool
where T : PrimitiveTypeTag<T> + Default
{
if let None = primitive.accessor
{
let (c_path, _path) = get_cstr(Some(path));
if validate_type && !self._add_type_shape_check(pipe, c_path, primitive)
{
return false;
}
let accessor = unsafe { pstd_type_model_get_accessor(self.object, pipe, c_path) };
if accessor as i32 == -1
{
return false;
}
let mut new_val = Some(accessor);
::std::mem::swap(&mut primitive.accessor, &mut new_val);
return true;
}
return false;
}
}
pub struct Primitive<ActualType : PrimitiveTypeTag<ActualType> + Default> {
accessor : Option<pstd_type_accessor_t>,
shape : PrimitiveTypeShape,
_phantom : PhantomData<ActualType>
}
impl <T : PrimitiveTypeTag<T> + Default> Primitive<T> {
pub fn new() -> Primitive<T>
{
return Primitive {
accessor : None,
shape : Default::default(),
_phantom : PhantomData
};
}
pub fn get(&self, type_inst:&mut TypeInstanceObject) -> Option<T>
{
if let Some(ref acc_ref) = self.accessor
{
let mut buf:T = Default::default();
let mut buf_ptr = &mut buf as *mut T;
let acc = acc_ref.clone();
if type_inst.read(acc, buf_ptr as *mut ::std::os::raw::c_void, ::std::mem::size_of::<T>())
{
return Some(buf);
}
}
return None;
}
pub fn set(&self, type_inst:&mut TypeInstanceObject, val:T) -> bool
{
if let Some(ref acc_ref) = self.accessor
{
let acc = acc_ref.clone();
let val_ref = &val;
let val_ptr = val_ref as *const T;
if type_inst.write(acc, val_ptr as *mut ::std::os::raw::c_void, ::std::mem::size_of::<T>())
{
return true;
}
}
return false;
}
}
pub trait PrimitiveTypeTag<T:Sized + Default>
{
fn validate_type_shape(shape : &PrimitiveTypeShape) -> bool;
}
impl pstd_type_field_t {
fn type_size(&self) -> u32 { self.size }
}
macro_rules! primitive_type {
($($type:ty => [$($var:ident : $val:expr);*]);*;) => {
$(impl PrimitiveTypeTag<$type> for $type {
fn validate_type_shape(ts : &PrimitiveTypeShape) -> bool
{
return $((ts.$var() == $val)&&)* true;
}
})*
}
}
primitive_type!{
i8 => [type_size:1; is_numeric:1; is_signed:1; is_float:0; is_primitive_token:0; is_compound:0];
i16 => [type_size:2; is_numeric:1; is_signed:1; is_float:0; is_primitive_token:0; is_compound:0];
i32 => [type_size:4; is_numeric:1; is_signed:1; is_float:0; is_primitive_token:0; is_compound:0];
i64 => [type_size:8; is_numeric:1; is_signed:1; is_float:0; is_primitive_token:0; is_compound:0];
u8 => [type_size:1; is_numeric:1; is_signed:0; is_float:0; is_primitive_token:0; is_compound:0];
u16 => [type_size:2; is_numeric:1; is_signed:0; is_float:0; is_primitive_token:0; is_compound:0];
u32 => [type_size:4; is_numeric:1; is_signed:0; is_float:0; is_primitive_token:0; is_compound:0];
u64 => [type_size:8; is_numeric:1; is_signed:0; is_float:0; is_primitive_token:0; is_compound:0];
f32 => [type_size:4; is_numeric:1; is_signed:1; is_float:1; is_primitive_token:0; is_compound:0];
f64 => [type_size:8; is_numeric:1; is_signed:1; is_float:1; is_primitive_token:0; is_compound:0];
}
pub trait DataModel<T:ProtocolModel> where Self:Sized {
fn new_data_model(model : Rc<T>, type_inst:TypeInstanceObject) -> Self;
}
pub trait ProtocolModel {
fn init_model(&mut self, pipes: HashMap<String, PipeDescriptor>) -> bool;
fn new_protocol_model(type_model:TypeModelObject) -> Self;
}
pub type Untyped = ();
impl ProtocolModel for () {
fn init_model(&mut self, _p:HashMap<String, PipeDescriptor>) -> bool { true }
fn new_protocol_model(_tm:TypeModelObject) -> Untyped {}
}
impl DataModel<Untyped> for Untyped {
fn new_data_model(_m : Rc<Untyped>, _ti: TypeInstanceObject) -> Untyped {}
}
#[macro_export]
macro_rules! protodef {
($(protodef $proto_name:ident { $([$pipe:ident.$($field:tt)*]:$type:ty => $model_name:ident;)* })*) => {
mod plumber_protocol {
use ::plumber_rs::protocol::{Primitive, TypeModelObject, ProtocolModel};
use ::plumber_rs::pipe::PipeDescriptor;
use ::std::collections::HashMap;
$(
pub struct $proto_name {
type_model : TypeModelObject,
$(pub $model_name : Primitive<$type>,)*
}
impl ProtocolModel for $proto_name {
fn init_model(&mut self,
pipes: HashMap<String, PipeDescriptor>) -> bool
{
$(
if let Some(pipe) = pipes.get(stringify!($pipe))
{
if !self.type_model.assign_primitive(*pipe, stringify!($($field)*), &mut self.$model_name, true)
{
return false;
}
}
else
{
return false;
}
)*
return true;
}
fn new_protocol_model(type_model : TypeModelObject) -> Self
{
return $proto_name {
type_model : type_model,
$(
$model_name : Primitive::new()
),*
};
}
}
)*
}
mod plumber_protocol_accessor {
use ::plumber_rs::protocol::{DataModel, TypeInstanceObject, PrimitiveTypeTag, Primitive};
use std::rc::Rc;
pub struct FieldAccessor<'a, T: PrimitiveTypeTag<T> + Default + 'a> {
target : &'a Primitive<T>,
inst : &'a mut TypeInstanceObject
}
impl <'a, T: PrimitiveTypeTag<T> + Default> FieldAccessor<'a, T> {
pub fn get(&mut self) -> Option<T>
{
return self.target.get(self.inst);
}
pub fn set(&mut self, val:T) -> bool
{
return self.target.set(self.inst, val);
}
}
$(
pub struct $proto_name {
model : Rc<::plumber_protocol::$proto_name>,
inst : TypeInstanceObject
}
impl $proto_name {
$(
#[allow(dead_code)]
pub fn $model_name(&mut self) -> FieldAccessor<$type>
{
return FieldAccessor::<$type>{
target: &self.model.$model_name,
inst : &mut self.inst
};
}
)*
}
impl DataModel<::plumber_protocol::$proto_name> for $proto_name {
fn new_data_model(model : Rc<::plumber_protocol::$proto_name>, type_inst:TypeInstanceObject) -> $proto_name
{
return $proto_name{
model : model,
inst : type_inst
};
}
}
)*
}
}
}
#[macro_export]
macro_rules! use_protocol {
($name:ident) => {
type ProtocolType = ::plumber_protocol::$name;
type DataModelType = ::plumber_protocol_accessor::$name;
}
}
#[macro_export]
macro_rules! no_protocol {
() => {
type ProtocolType = ::plumber_rs::protocol::Untyped;
type DataModelType = ::plumber_rs::protocol::Untyped;
}
}
#[macro_export]
macro_rules! init_protocol {
($what:ident {$($actual:expr => $model:ident),*}) => {
{
let mut pipe_map = ::std::collections::HashMap::<String, ::plumber_rs::pipe::PipeDescriptor>::new();
$(pipe_map.insert(stringify!($model).to_string(), $actual.as_descriptor());)*
if !$what.init_model(pipe_map)
{
return ::plumber_rs::servlet::fail();
}
}
}
}