diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3940569..95c90cf 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -23,9 +23,5 @@
     },
     "[rust]": {
         "editor.defaultFormatter": "rust-lang.rust-analyzer"
-    },
-    "files.associations": {
-        "*.inc": "c",
-        "random": "c"
     }
 }
diff --git a/crates/lune-std-ffi/readme.md b/crates/lune-std-ffi/readme.md
deleted file mode 100644
index e61256b..0000000
--- a/crates/lune-std-ffi/readme.md
+++ /dev/null
@@ -1,129 +0,0 @@
-TODO: rewrite docs
-
-# Raw
-
-Data received from external. You can move this data into a box, use it as a ref, or change it directly to a Lua value.
-The raw data is not on Lua's heap.
-
-Raw:toRef()
-Convert data into ref. it allocate new lua userdata
-
-Raw:toBox()
-Convert data into box. it allocate new lua userdata
-
-Raw:intoBox()
-Raw:intoRef()
-
-See type:fromRaw()
-
-# Box
-
-`ffi.box(size)`
-
-Create new userdata with sized by `size` argument. Box is untyped, and have no ABI information. You can write some data into box with `type`
-
-All operation with box will boundary checked. GC will free heap well.
-
-일반적으로 포인터를 넘겨주기 위해서 사용됩니다. 박스의 공간은 ref 할 수 있으며. 함수를 수행한 후 루아에서 읽어볼 수 있습니다.
-
-## :zero()
-박스를 0 으로 채워넣습니다. 기본적으로 박스는 초기화될 때 0 으로 채워지기 때문에 박스를 다시 0 으로 초기화하고 싶을 경우에 사용하십시오.
-
-## :copy(targetbox,size,offset?=0,targetoffset?=0)
-박스 안의 값을 다른 박스에 복사합니다. 바운더리가 확인되어지므로 안전합니다.
-
-## .size
-이 박스의 크기입니다.
-
-## :ref(offset?=0) => ref
-이 박스를 참조합니다. 참조가 살아있는 동안 박스는 수거되지 않습니다. 일반적으로 외부의 함수에 포인터를 넘겨주기 위해서 사용됩니다.
-
-## more stuffs (not planned at this time)
-
-ref=>buffer conversion, or bit/byte related?
-
-# Ref (Unsafe)
-
-바운더리를 처리하지 않는 포인터입니다. 외부에서 받은 포인터, 또는 박스로부터 만들어진 포인터입니다.
-ref 는 바운더리를 검사하지 않으므로 안전하지 않습니다.
-
-## :offset(bytes)
-
-이 ref 와 상대적인 위치에 있는 ref 를 구합니다.
-
-## :writefromRef()
-다른 ref 안의 값을 읽어와 이 ref 안에 씁니다. 아래와 비슷한 연산을 합니다
-```c
-int a = 100,b;
-```
-
-## :writefromBox()
-box 값을 읽어와서 쓰기
-
-# Type
-
-`type` is abstract class that helps encoding data into `box` or decode data from `box`
-
-## :toBox(luavalue)
-Convert lua value to box. box will sized with `type.size`
-
-## :fromBox(box,offset?=0)
-Read data from box, and convert into lua value.
-Boundary will checked
-
-## :intoBox(luavalue,box,offset?=0)
-Convert lua value, and write into box
-Boundary will checked
-
-## :fromRef(ref,offset?=0)
-포인터가 가르키는 곳의 데이터를 읽어서 루아의 데이터로 변환합니다.
-
-## :intoRef(luavalue,ref,offset?=0)
-포인터가 가르키는 곳에 데이터를 작성합니다.
-
-## :fromRaw(raw,offset?=0)
-
-
-## :ptr() -> Ptr
-Get pointer type
-
-## :arr(len) -> Arr
-Get array type
-
-## .size
-
-Byte size of this type. you can initialize box with
-
-## :cast(box,type) TODO
-
-# Ptr
-Pointer type of some type.
-
-Ptr is not data converter. It only works for type hint of `struct` or `fn`
-
-## .inner
-Inner type
-
-## .size
-Size of `usize`
-
-:ptr()
-:arr()
-
-## Arr
-
-## Void
-
-`ffi.void`
-
-Zero sized type.
-
-## Fn
-Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function.
-
-`ffi.fn({ type }, type) -> fn`
-
-:toLua( ref ) -> luafunction
-:toBox( luafunction ) -> ref
-
-> TODO: rust, and another ABI support
diff --git a/crates/lune-std-ffi/src/c/c_struct.rs b/crates/lune-std-ffi/src/c/c_struct.rs
index 168d7d2..16e2f8f 100644
--- a/crates/lune-std-ffi/src/c/c_struct.rs
+++ b/crates/lune-std-ffi/src/c/c_struct.rs
@@ -113,16 +113,6 @@ impl CStruct {
 impl LuaUserData for CStruct {
     fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
         fields.add_field_method_get("size", |_, this| Ok(this.size));
-
-        // Simply pass in the locked table used when first creating this object.
-        // By strongly referencing the table, the types inside do not disappear
-        // and the user can read the contents as needed. (good recycling!)
-        fields.add_field_function_get("inner", |lua, this: LuaAnyUserData| {
-            let table: LuaValue = get_association(lua, CSTRUCT_INNER, this)?
-                // It shouldn't happen.
-                .ok_or(LuaError::external("inner field not found"))?;
-            Ok(table)
-        });
     }
 
     fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
@@ -130,6 +120,18 @@ impl LuaUserData for CStruct {
             let offset = this.offset(index)?;
             Ok(offset)
         });
+        // Simply pass type in the locked table used when first creating this object.
+        // By referencing the table to struct, the types inside do not disappear
+        methods.add_function("field", |lua, (this, field): (LuaAnyUserData, usize)| {
+            if let LuaValue::Table(t) = get_association(lua, CSTRUCT_INNER, this)?
+                .ok_or(LuaError::external("Field table not found"))?
+            {
+                let value: LuaValue = t.get(field + 1)?;
+                Ok(value)
+            } else {
+                Err(LuaError::external("Failed to read field table"))
+            }
+        });
         methods.add_function("ptr", |lua, this: LuaAnyUserData| {
             let pointer = CPtr::from_lua_userdata(lua, &this)?;
             Ok(pointer)
diff --git a/crates/lune-std-ffi/src/c/c_type.rs b/crates/lune-std-ffi/src/c/c_type.rs
index 5300bea..17c6171 100644
--- a/crates/lune-std-ffi/src/c/c_type.rs
+++ b/crates/lune-std-ffi/src/c/c_type.rs
@@ -1,28 +1,19 @@
 #![allow(clippy::cargo_common_metadata)]
 
-use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
-use num::cast::AsPrimitive;
 use std::marker::PhantomData;
 
 use libffi::middle::Type;
+use lune_utils::fmt::{pretty_format_value, ValueFormatConfig};
 use mlua::prelude::*;
+use num::cast::AsPrimitive;
 
-use super::association_names::CTYPE_STATIC;
-use super::c_arr::CArr;
-use super::c_helper::get_ensured_size;
-use super::c_ptr::CPtr;
-use crate::ffi::ffi_association::set_association;
-use crate::ffi::ffi_helper::get_ptr_from_userdata;
-
-pub struct CType<T: ?Sized> {
-    // for ffi_ptrarray_to_raw?
-    // libffi_cif: Cif,
-    libffi_type: Type,
-    size: usize,
-    name: Option<&'static str>,
-    signedness: bool,
-    _phantom: PhantomData<T>,
-}
+use super::{
+    association_names::CTYPE_STATIC, c_arr::CArr, c_helper::get_ensured_size, c_ptr::CPtr,
+};
+use crate::ffi::{
+    ffi_association::set_association,
+    ffi_native::{NativeCast, NativeConvert},
+};
 
 // We can't get a CType<T> through mlua, something like
 // .is::<CType<dyn Any>> will fail.
@@ -35,28 +26,34 @@ pub struct CTypeStatic {
     pub name: Option<&'static str>,
     pub signedness: bool,
 }
-
 impl CTypeStatic {
-    fn new<T>(ctype: &CType<T>) -> Self {
+    fn new<T>(ctype: &CType<T>, signedness: bool) -> Self {
         Self {
             libffi_type: ctype.libffi_type.clone(),
             size: ctype.size,
             name: ctype.name,
-            signedness: ctype.signedness,
+            signedness,
         }
     }
 }
 impl LuaUserData for CTypeStatic {}
 
+pub struct CType<T: ?Sized> {
+    // for ffi_ptrarray_to_raw?
+    // libffi_cif: Cif,
+    libffi_type: Type,
+    size: usize,
+    name: Option<&'static str>,
+    _phantom: PhantomData<T>,
+}
 impl<T> CType<T>
 where
     T: 'static,
-    Self: CTypeConvert + CTypeCast,
+    Self: NativeConvert + CTypeCast + CTypeSignedness,
 {
     pub fn new_with_libffi_type<'lua>(
         lua: &'lua Lua,
         libffi_type: Type,
-        signedness: bool,
         name: Option<&'static str>,
     ) -> LuaResult<LuaAnyUserData<'lua>> {
         // let libffi_cfi = Cif::new(vec![libffi_type.clone()], Type::void());
@@ -67,10 +64,10 @@ where
             libffi_type,
             size,
             name,
-            signedness,
             _phantom: PhantomData,
         };
-        let userdata_static = lua.create_any_userdata(CTypeStatic::new::<T>(&ctype))?;
+        let userdata_static =
+            lua.create_any_userdata(CTypeStatic::new::<T>(&ctype, ctype.get_signedness()))?;
         let userdata = lua.create_userdata(ctype)?;
 
         set_association(lua, CTYPE_STATIC, &userdata, &userdata_static)?;
@@ -85,57 +82,13 @@ where
         }
     }
 }
+impl<T> NativeCast for CType<T> {}
 
-// Handle C data, provide type conversion between luavalue and c-type
-pub trait CTypeConvert {
-    // Convert luavalue into data, then write into ptr
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()>;
-
-    // Read data from ptr, then convert into luavalue
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue>;
-
-    // Read data from userdata (such as box or ref) and convert it into luavalue
-    unsafe fn read_userdata<'lua>(
-        &self,
-        lua: &'lua Lua,
-        userdata: LuaAnyUserData<'lua>,
-        offset: Option<isize>,
-    ) -> LuaResult<LuaValue<'lua>> {
-        let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
-        let value = Self::ptr_into_luavalue(lua, ptr)?;
-        Ok(value)
-    }
-
-    // Write data into userdata (such as box or ref) from luavalue
-    unsafe fn write_userdata<'lua>(
-        &self,
-        luavalue: LuaValue<'lua>,
-        userdata: LuaAnyUserData<'lua>,
-        offset: Option<isize>,
-    ) -> LuaResult<()> {
-        let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
-        Self::luavalue_into_ptr(luavalue, ptr)?;
-        Ok(())
-    }
-}
-
-pub trait CTypeCast {
-    // Cast T as U
-    fn cast_num<T, U>(&self, from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()>
-    where
-        T: AsPrimitive<U>,
-        U: 'static + Copy,
-    {
-        let from_ptr = unsafe { get_ptr_from_userdata(from, None)?.cast::<T>() };
-        let into_ptr = unsafe { get_ptr_from_userdata(into, None)?.cast::<U>() };
-
-        unsafe {
-            *into_ptr = (*from_ptr).as_();
-        }
-
-        Ok(())
-    }
-
+// Cast native data
+pub trait CTypeCast
+where
+    Self: NativeCast,
+{
     fn try_cast_num<T, U>(
         &self,
         ctype: &LuaAnyUserData,
@@ -154,7 +107,6 @@ pub trait CTypeCast {
         }
     }
 
-    #[allow(unused_variables)]
     fn cast(
         &self,
         from_ctype: &LuaAnyUserData,
@@ -179,31 +131,52 @@ pub trait CTypeCast {
     }
 }
 
+pub trait CTypeSignedness {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
 impl<T> LuaUserData for CType<T>
 where
     T: 'static,
-    Self: CTypeConvert + CTypeCast,
+    Self: CTypeCast + CTypeSignedness + NativeCast + NativeConvert,
 {
     fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
         fields.add_field_method_get("size", |_, this| Ok(this.size));
         fields.add_meta_field(LuaMetaMethod::Type, "CType");
-        fields.add_field_method_get("signedness", |_, this| Ok(this.signedness));
+        fields.add_field_method_get("signedness", |_, this| Ok(this.get_signedness()));
     }
 
     fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
         methods.add_function("ptr", |lua, this: LuaAnyUserData| {
             CPtr::from_lua_userdata(lua, &this)
         });
-        methods.add_method(
+        methods.add_function(
             "from",
-            |lua, ctype, (userdata, offset): (LuaAnyUserData, Option<isize>)| unsafe {
-                ctype.read_userdata(lua, userdata, offset)
+            |lua,
+             (ctype, userdata, offset): (
+                LuaAnyUserData,
+                LuaAnyUserData,
+                Option<isize>,
+            )| unsafe {
+                ctype
+                    .borrow::<CType<T>>()?
+                    .read_userdata(&ctype, lua, &userdata, offset)
             },
         );
-        methods.add_method(
+        methods.add_function(
             "into",
-            |_, ctype, (value, userdata, offset): (LuaValue, LuaAnyUserData, Option<isize>)| unsafe {
-                ctype.write_userdata(value, userdata, offset)
+            |lua,
+             (ctype, value, userdata, offset): (
+                LuaAnyUserData,
+                LuaValue,
+                LuaAnyUserData,
+                Option<isize>,
+            )| unsafe {
+                ctype
+                    .borrow::<CType<T>>()?
+                    .write_userdata(&ctype, lua, value, userdata, offset)
             },
         );
         methods.add_function("arr", |lua, (this, length): (LuaAnyUserData, usize)| {
diff --git a/crates/lune-std-ffi/src/c/mod.rs b/crates/lune-std-ffi/src/c/mod.rs
index 35ba063..7b510d7 100644
--- a/crates/lune-std-ffi/src/c/mod.rs
+++ b/crates/lune-std-ffi/src/c/mod.rs
@@ -1,14 +1,15 @@
-pub(super) mod c_arr;
-pub(super) mod c_fn;
-pub(super) mod c_helper;
-pub(super) mod c_ptr;
-pub(super) mod c_string;
-pub(super) mod c_struct;
-pub(super) mod c_type;
-pub(super) mod types;
-
+pub use types::create_all_c_types;
 pub use types::create_all_types;
 
+pub mod c_arr;
+pub mod c_fn;
+pub mod c_helper;
+pub mod c_ptr;
+pub mod c_string;
+pub mod c_struct;
+pub mod c_type;
+pub mod types;
+
 // Named registry table names
 mod association_names {
     pub const CPTR_INNER: &str = "__cptr_inner";
diff --git a/crates/lune-std-ffi/src/c/types/c_char.rs b/crates/lune-std-ffi/src/c/types/c_char.rs
deleted file mode 100644
index adaec6a..0000000
--- a/crates/lune-std-ffi/src/c/types/c_char.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-use core::ffi::*;
-
-use libffi::middle::Type;
-use mlua::prelude::*;
-use num::cast::AsPrimitive;
-
-use super::super::c_type::{CType, CTypeCast, CTypeConvert};
-use crate::ffi::ffi_platform::CHAR_IS_SIGNED;
-
-impl CTypeConvert for CType<c_char> {
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
-        let value: c_char = match value {
-            LuaValue::Integer(t) => t.as_(),
-            LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
-            _ => {
-                return Err(LuaError::external(format!(
-                    "Argument LuaValue expected a Integer or String, got {}",
-                    value.type_name()
-                )))
-            }
-        };
-        unsafe {
-            *(ptr.cast::<c_char>()) = value;
-        }
-        Ok(())
-    }
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
-        let value = unsafe { (*ptr.cast::<c_char>()).into_lua(lua)? };
-        Ok(value)
-    }
-}
-
-impl CTypeCast for CType<c_char> {
-    fn cast(
-        &self,
-        from_ctype: &LuaAnyUserData,
-        into_ctype: &LuaAnyUserData,
-        from: &LuaAnyUserData,
-        into: &LuaAnyUserData,
-    ) -> LuaResult<()> {
-        self.try_cast_num::<c_char, c_float>(into_ctype, from, into)?
-            .or(self.try_cast_num::<c_char, c_double>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_char, c_char>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_char, c_long>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_char, c_int>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_char, c_longlong>(into_ctype, from, into)?)
-            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
-    }
-}
-
-pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
-    Ok((
-        "char",
-        CType::<c_char>::new_with_libffi_type(
-            lua,
-            if CHAR_IS_SIGNED {
-                Type::c_schar()
-            } else {
-                Type::c_uchar()
-            },
-            CHAR_IS_SIGNED,
-            Some("char"),
-        )?,
-    ))
-}
diff --git a/crates/lune-std-ffi/src/c/types/c_double.rs b/crates/lune-std-ffi/src/c/types/c_double.rs
deleted file mode 100644
index 9f63f99..0000000
--- a/crates/lune-std-ffi/src/c/types/c_double.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use core::ffi::*;
-
-use libffi::middle::Type;
-use mlua::prelude::*;
-
-use super::super::c_type::{CType, CTypeCast, CTypeConvert};
-use num::cast::AsPrimitive;
-
-impl CTypeConvert for CType<c_double> {
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
-        let value: c_double = match value {
-            LuaValue::Integer(t) => t.as_(),
-            LuaValue::Number(t) => t.as_(),
-            LuaValue::String(t) => t
-                .to_string_lossy()
-                .parse::<c_double>()
-                .map_err(LuaError::external)?,
-            _ => {
-                return Err(LuaError::external(format!(
-                    "Argument LuaValue expected a Integer, Number or String, got {}",
-                    value.type_name()
-                )))
-            }
-        };
-        unsafe {
-            *(ptr.cast::<c_double>()) = value;
-        }
-        Ok(())
-    }
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
-        let value = unsafe { (*ptr.cast::<c_double>()).into_lua(lua)? };
-        Ok(value)
-    }
-}
-
-impl CTypeCast for CType<c_double> {
-    fn cast(
-        &self,
-        from_ctype: &LuaAnyUserData,
-        into_ctype: &LuaAnyUserData,
-        from: &LuaAnyUserData,
-        into: &LuaAnyUserData,
-    ) -> LuaResult<()> {
-        self.try_cast_num::<c_double, c_float>(into_ctype, from, into)?
-            .or(self.try_cast_num::<c_double, c_double>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_double, c_char>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_double, c_long>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_double, c_int>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_double, c_longlong>(into_ctype, from, into)?)
-            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
-    }
-}
-
-pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
-    Ok((
-        "double",
-        CType::<c_double>::new_with_libffi_type(lua, Type::f64(), true, Some("double"))?,
-    ))
-}
diff --git a/crates/lune-std-ffi/src/c/types/c_float.rs b/crates/lune-std-ffi/src/c/types/c_float.rs
deleted file mode 100644
index c02fc80..0000000
--- a/crates/lune-std-ffi/src/c/types/c_float.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use core::ffi::*;
-
-use libffi::middle::Type;
-use mlua::prelude::*;
-
-use super::super::c_type::{CType, CTypeCast, CTypeConvert};
-use num::cast::AsPrimitive;
-
-impl CTypeConvert for CType<c_float> {
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
-        let value: c_float = match value {
-            LuaValue::Integer(t) => t.as_(),
-            LuaValue::Number(t) => t.as_(),
-            LuaValue::String(t) => t
-                .to_string_lossy()
-                .parse::<c_float>()
-                .map_err(LuaError::external)?,
-            _ => {
-                return Err(LuaError::external(format!(
-                    "Argument LuaValue expected a Integer, Number or String, got {}",
-                    value.type_name()
-                )))
-            }
-        };
-        unsafe {
-            *(ptr.cast::<c_float>()) = value;
-        }
-        Ok(())
-    }
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
-        let value = unsafe { (*ptr.cast::<c_float>()).into_lua(lua)? };
-        Ok(value)
-    }
-}
-
-impl CTypeCast for CType<c_float> {
-    fn cast(
-        &self,
-        from_ctype: &LuaAnyUserData,
-        into_ctype: &LuaAnyUserData,
-        from: &LuaAnyUserData,
-        into: &LuaAnyUserData,
-    ) -> LuaResult<()> {
-        self.try_cast_num::<c_float, c_float>(into_ctype, from, into)?
-            .or(self.try_cast_num::<c_float, c_double>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_float, c_char>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_float, c_long>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_float, c_int>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_float, c_longlong>(into_ctype, from, into)?)
-            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
-    }
-}
-
-pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
-    Ok((
-        "float",
-        CType::<c_float>::new_with_libffi_type(lua, Type::f32(), true, Some("float"))?,
-    ))
-}
diff --git a/crates/lune-std-ffi/src/c/types/c_int.rs b/crates/lune-std-ffi/src/c/types/c_int.rs
deleted file mode 100644
index ac3551d..0000000
--- a/crates/lune-std-ffi/src/c/types/c_int.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use core::ffi::*;
-
-use libffi::middle::Type;
-use mlua::prelude::*;
-use num::cast::AsPrimitive;
-
-use super::super::c_type::{CType, CTypeCast, CTypeConvert};
-
-impl CTypeConvert for CType<c_int> {
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
-        let value: c_int = match value {
-            LuaValue::Integer(t) => t.as_(),
-            LuaValue::Number(t) => t.as_(),
-            LuaValue::String(t) => t
-                .to_string_lossy()
-                .parse::<i32>()
-                .map_err(LuaError::external)?,
-            _ => {
-                return Err(LuaError::external(format!(
-                    "Argument LuaValue expected a Integer, Number or String, got {}",
-                    value.type_name()
-                )))
-            }
-        };
-        unsafe {
-            *(ptr.cast::<c_int>()) = value;
-        }
-        Ok(())
-    }
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
-        let value = unsafe { (*ptr.cast::<c_int>()).into_lua(lua)? };
-        Ok(value)
-    }
-}
-
-impl CType<c_int> {}
-
-impl CTypeCast for CType<c_int> {
-    fn cast(
-        &self,
-        from_ctype: &LuaAnyUserData,
-        into_ctype: &LuaAnyUserData,
-        from: &LuaAnyUserData,
-        into: &LuaAnyUserData,
-    ) -> LuaResult<()> {
-        self.try_cast_num::<c_int, c_float>(into_ctype, from, into)?
-            .or(self.try_cast_num::<c_int, c_double>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_int, c_char>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_int, c_long>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_int, c_int>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_int, c_longlong>(into_ctype, from, into)?)
-            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
-    }
-}
-
-pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
-    Ok((
-        "int",
-        CType::<c_int>::new_with_libffi_type(
-            lua,
-            Type::c_int(),
-            c_int::MIN.unsigned_abs() != 0,
-            Some("int"),
-        )?,
-    ))
-}
diff --git a/crates/lune-std-ffi/src/c/types/c_long.rs b/crates/lune-std-ffi/src/c/types/c_long.rs
deleted file mode 100644
index 60691c7..0000000
--- a/crates/lune-std-ffi/src/c/types/c_long.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use core::ffi::*;
-
-use libffi::middle::Type;
-use mlua::prelude::*;
-
-use super::super::c_type::{CType, CTypeCast, CTypeConvert};
-use num::cast::AsPrimitive;
-
-impl CTypeConvert for CType<c_long> {
-    fn luavalue_into_ptr(value: LuaValue, ptr: *mut ()) -> LuaResult<()> {
-        let value: c_long = match value {
-            LuaValue::Integer(t) => t.as_(),
-            LuaValue::Number(t) => t.as_(),
-            LuaValue::String(t) => t
-                .to_string_lossy()
-                .parse::<c_long>()
-                .map_err(LuaError::external)?,
-            _ => {
-                return Err(LuaError::external(format!(
-                    "Argument LuaValue expected a Integer, Number or String, got {}",
-                    value.type_name()
-                )))
-            }
-        };
-        unsafe {
-            *(ptr.cast::<c_long>()) = value;
-        }
-        Ok(())
-    }
-    fn ptr_into_luavalue(lua: &Lua, ptr: *mut ()) -> LuaResult<LuaValue> {
-        let value = unsafe { (*ptr.cast::<c_long>()).into_lua(lua)? };
-        Ok(value)
-    }
-}
-
-impl CTypeCast for CType<c_long> {
-    fn cast(
-        &self,
-        from_ctype: &LuaAnyUserData,
-        into_ctype: &LuaAnyUserData,
-        from: &LuaAnyUserData,
-        into: &LuaAnyUserData,
-    ) -> LuaResult<()> {
-        self.try_cast_num::<c_long, c_float>(into_ctype, from, into)?
-            .or(self.try_cast_num::<c_long, c_double>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_long, c_char>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_long, c_long>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_long, c_int>(into_ctype, from, into)?)
-            .or(self.try_cast_num::<c_long, c_longlong>(into_ctype, from, into)?)
-            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
-    }
-}
-
-pub fn get_export(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
-    Ok((
-        "long",
-        CType::<c_long>::new_with_libffi_type(lua, Type::c_long(), true, Some("long"))?,
-    ))
-}
diff --git a/crates/lune-std-ffi/src/c/types/f32.rs b/crates/lune-std-ffi/src/c/types/f32.rs
new file mode 100644
index 0000000..79baa3e
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/f32.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<f32> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<f32> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: f32 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<f32>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<f32>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<f32>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "f32",
+        CType::<f32>::new_with_libffi_type(lua, Type::f32(), Some("f32"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/f64.rs b/crates/lune-std-ffi/src/c/types/f64.rs
new file mode 100644
index 0000000..7dec899
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/f64.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<f64> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<f64> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: f64 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<f64>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<f64>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<f64>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "f64",
+        CType::<f64>::new_with_libffi_type(lua, Type::f64(), Some("f64"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/i128.rs b/crates/lune-std-ffi/src/c/types/i128.rs
new file mode 100644
index 0000000..8f75d9c
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/i128.rs
@@ -0,0 +1,61 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<i128> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<i128> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: i128 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<i128>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<i128>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<i128>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "i128",
+        CType::<i128>::new_with_libffi_type(
+            lua,
+            Type::structure(vec![Type::u64(), Type::u64()]),
+            Some("i128"),
+        )?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/i16.rs b/crates/lune-std-ffi/src/c/types/i16.rs
new file mode 100644
index 0000000..e9a33cc
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/i16.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<i16> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<i16> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: i16 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<i16>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<i16>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<i16>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "i16",
+        CType::<i16>::new_with_libffi_type(lua, Type::i16(), Some("f32"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/i32.rs b/crates/lune-std-ffi/src/c/types/i32.rs
new file mode 100644
index 0000000..6478370
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/i32.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<i32> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<i32> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: i32 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<i32>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<i32>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<i32>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "i32",
+        CType::<i32>::new_with_libffi_type(lua, Type::i32(), Some("i32"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/i64.rs b/crates/lune-std-ffi/src/c/types/i64.rs
new file mode 100644
index 0000000..ff1e228
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/i64.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<i64> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<i64> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: i64 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<i64>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<i64>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<i64>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "i64",
+        CType::<i64>::new_with_libffi_type(lua, Type::i64(), Some("i64"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/i8.rs b/crates/lune-std-ffi/src/c/types/i8.rs
new file mode 100644
index 0000000..0c8cc28
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/i8.rs
@@ -0,0 +1,53 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<i8> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<i8> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: i8 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<i8>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<i8>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "i8",
+        CType::<i8>::new_with_libffi_type(lua, Type::i8(), Some("i8"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/isize.rs b/crates/lune-std-ffi/src/c/types/isize.rs
new file mode 100644
index 0000000..634d7bf
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/isize.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<isize> {
+    fn get_signedness(&self) -> bool {
+        true
+    }
+}
+
+impl NativeConvert for CType<isize> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: isize = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<isize>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<isize>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<isize>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "isize",
+        CType::<isize>::new_with_libffi_type(lua, Type::isize(), Some("isize"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/mod.rs b/crates/lune-std-ffi/src/c/types/mod.rs
index af90e57..a059967 100644
--- a/crates/lune-std-ffi/src/c/types/mod.rs
+++ b/crates/lune-std-ffi/src/c/types/mod.rs
@@ -1,18 +1,156 @@
-mod c_char;
-mod c_double;
-mod c_float;
-mod c_int;
-mod c_long;
+use core::ffi::*;
+use std::any::TypeId;
 
+use libffi::middle::Type;
 use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::c_type::CType;
+use super::c_type::CTypeCast;
+
+pub mod f32;
+pub mod f64;
+pub mod i128;
+pub mod i16;
+pub mod i32;
+pub mod i64;
+pub mod i8;
+pub mod isize;
+pub mod u128;
+pub mod u16;
+pub mod u32;
+pub mod u64;
+pub mod u8;
+pub mod usize;
+
+impl<T> CTypeCast for CType<T>
+where
+    T: AsPrimitive<u8>
+        + AsPrimitive<u16>
+        + AsPrimitive<u32>
+        + AsPrimitive<u64>
+        + AsPrimitive<u128>
+        + AsPrimitive<i8>
+        + AsPrimitive<i16>
+        + AsPrimitive<i32>
+        + AsPrimitive<i64>
+        + AsPrimitive<i128>
+        + AsPrimitive<f32>
+        + AsPrimitive<f64>
+        + AsPrimitive<usize>
+        + AsPrimitive<isize>,
+{
+    fn cast(
+        &self,
+        from_ctype: &LuaAnyUserData,
+        into_ctype: &LuaAnyUserData,
+        from: &LuaAnyUserData,
+        into: &LuaAnyUserData,
+    ) -> LuaResult<()> {
+        self.try_cast_num::<T, u8>(into_ctype, from, into)?
+            .or(self.try_cast_num::<T, u16>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, u32>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, u64>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, u128>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, i8>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, i16>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, i32>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, i64>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, i128>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, f32>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, f64>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, usize>(into_ctype, from, into)?)
+            .or(self.try_cast_num::<T, isize>(into_ctype, from, into)?)
+            .ok_or_else(|| self.cast_failed_with(from_ctype, into_ctype))
+    }
+}
+
+// export all default c-types
+pub fn create_all_c_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
+    Ok(vec![
+        (
+            "char",
+            CType::<c_char>::new_with_libffi_type(
+                lua,
+                if TypeId::of::<c_char>() == TypeId::of::<u8>() {
+                    Type::c_uchar()
+                } else {
+                    Type::c_schar()
+                },
+                Some("longlong"),
+            )?,
+        ),
+        (
+            "uchar",
+            CType::<c_uchar>::new_with_libffi_type(lua, Type::c_uchar(), Some("uchar"))?,
+        ),
+        (
+            "schar",
+            CType::<c_schar>::new_with_libffi_type(lua, Type::c_schar(), Some("schar"))?,
+        ),
+        (
+            "short",
+            CType::<c_short>::new_with_libffi_type(lua, Type::c_short(), Some("short"))?,
+        ),
+        (
+            "ushort",
+            CType::<c_ushort>::new_with_libffi_type(lua, Type::c_ushort(), Some("ushort"))?,
+        ),
+        (
+            "int",
+            CType::<c_int>::new_with_libffi_type(lua, Type::c_int(), Some("int"))?,
+        ),
+        (
+            "uint",
+            CType::<c_uint>::new_with_libffi_type(lua, Type::c_uint(), Some("uint"))?,
+        ),
+        (
+            "long",
+            CType::<c_long>::new_with_libffi_type(lua, Type::c_long(), Some("long"))?,
+        ),
+        (
+            "ulong",
+            CType::<c_ulong>::new_with_libffi_type(lua, Type::c_ulong(), Some("ulong"))?,
+        ),
+        (
+            "longlong",
+            CType::<c_longlong>::new_with_libffi_type(lua, Type::c_longlong(), Some("longlong"))?,
+        ),
+        (
+            "ulonglong",
+            CType::<c_ulonglong>::new_with_libffi_type(
+                lua,
+                Type::c_ulonglong(),
+                Some("ulonglong"),
+            )?,
+        ),
+        (
+            "float",
+            CType::<c_float>::new_with_libffi_type(lua, Type::f32(), Some("float"))?,
+        ),
+        (
+            "double",
+            CType::<c_double>::new_with_libffi_type(lua, Type::f64(), Some("double"))?,
+        ),
+    ])
+}
 
 // export all default c-types
 pub fn create_all_types(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaAnyUserData)>> {
     Ok(vec![
-        c_char::get_export(lua)?,
-        c_double::get_export(lua)?,
-        c_float::get_export(lua)?,
-        c_int::get_export(lua)?,
-        c_long::get_export(lua)?,
+        self::u8::create_type(lua)?,
+        self::u16::create_type(lua)?,
+        self::u32::create_type(lua)?,
+        self::u64::create_type(lua)?,
+        self::u128::create_type(lua)?,
+        self::i8::create_type(lua)?,
+        self::i16::create_type(lua)?,
+        self::i32::create_type(lua)?,
+        self::i64::create_type(lua)?,
+        self::i128::create_type(lua)?,
+        self::f64::create_type(lua)?,
+        self::f32::create_type(lua)?,
+        self::usize::create_type(lua)?,
+        self::isize::create_type(lua)?,
     ])
 }
diff --git a/crates/lune-std-ffi/src/c/types/u128.rs b/crates/lune-std-ffi/src/c/types/u128.rs
new file mode 100644
index 0000000..80ff621
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/u128.rs
@@ -0,0 +1,61 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<u128> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<u128> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: u128 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<u128>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<u128>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<u128>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "u128",
+        CType::<u128>::new_with_libffi_type(
+            lua,
+            Type::structure(vec![Type::u64(), Type::u64()]),
+            Some("u128"),
+        )?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/u16.rs b/crates/lune-std-ffi/src/c/types/u16.rs
new file mode 100644
index 0000000..b2a172b
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/u16.rs
@@ -0,0 +1,58 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<u16> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<u16> {
+    // Convert luavalue into data, then write into ptr
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: u16 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<u16>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<u16>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<u16>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "u16",
+        CType::<u16>::new_with_libffi_type(lua, Type::u16(), Some("u16"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/u32.rs b/crates/lune-std-ffi/src/c/types/u32.rs
new file mode 100644
index 0000000..3f494c2
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/u32.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<u32> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<u32> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: u32 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<u32>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<u32>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<u32>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "u32",
+        CType::<u32>::new_with_libffi_type(lua, Type::u32(), Some("u32"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/u64.rs b/crates/lune-std-ffi/src/c/types/u64.rs
new file mode 100644
index 0000000..13cc41a
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/u64.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<u64> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<u64> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: u64 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<u64>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<u64>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<u64>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "u64",
+        CType::<u64>::new_with_libffi_type(lua, Type::u64(), Some("u64"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/u8.rs b/crates/lune-std-ffi/src/c/types/u8.rs
new file mode 100644
index 0000000..65c81d6
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/u8.rs
@@ -0,0 +1,56 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<u8> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<u8> {
+    // Convert luavalue into data, then write into ptr
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: u8 = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::String(t) => t.as_bytes().first().map_or(0, u8::to_owned).as_(),
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<u8>()) = value;
+        }
+        Ok(())
+    }
+
+    // Read data from ptr, then convert into luavalue
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<u8>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "u8",
+        CType::<u8>::new_with_libffi_type(lua, Type::u8(), Some("u8"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/c/types/usize.rs b/crates/lune-std-ffi/src/c/types/usize.rs
new file mode 100644
index 0000000..8b959d6
--- /dev/null
+++ b/crates/lune-std-ffi/src/c/types/usize.rs
@@ -0,0 +1,57 @@
+use libffi::middle::Type;
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::c_type::{CType, CTypeSignedness};
+use crate::ffi::ffi_native::NativeConvert;
+
+impl CTypeSignedness for CType<usize> {
+    fn get_signedness(&self) -> bool {
+        false
+    }
+}
+
+impl NativeConvert for CType<usize> {
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        _lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()> {
+        let value: usize = match value {
+            LuaValue::Integer(t) => t.as_(),
+            LuaValue::Number(t) => t.as_(),
+            LuaValue::String(t) => t
+                .to_string_lossy()
+                .parse::<usize>()
+                .map_err(LuaError::external)?,
+            _ => {
+                return Err(LuaError::external(format!(
+                    "Argument LuaValue expected a Integer, Number or String, got {}",
+                    value.type_name()
+                )))
+            }
+        };
+        unsafe {
+            *(ptr.cast::<usize>()) = value;
+        }
+        Ok(())
+    }
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        _this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>> {
+        let value = unsafe { (*ptr.cast::<usize>()).into_lua(lua)? };
+        Ok(value)
+    }
+}
+
+pub fn create_type(lua: &Lua) -> LuaResult<(&'static str, LuaAnyUserData)> {
+    Ok((
+        "usize",
+        CType::<usize>::new_with_libffi_type(lua, Type::usize(), Some("usize"))?,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_association.rs b/crates/lune-std-ffi/src/ffi/ffi_association.rs
index be242de..6990938 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_association.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_association.rs
@@ -1,5 +1,7 @@
 #![allow(clippy::cargo_common_metadata)]
 
+use mlua::prelude::*;
+
 // This is a small library that helps you set the dependencies of data in Lua.
 // In FFI, there is often data that is dependent on other data.
 // However, if you use user_value to inform Lua of the dependency,
@@ -22,7 +24,6 @@
 // Since the outermost pointer holds the definition for the pointer
 // type inside it, only the outermost type will be removed on the first gc.
 // It doesn't matter much. But if there is a cleaner way, we should choose it
-use mlua::prelude::*;
 
 // Forces 'associated' to persist as long as 'value' is alive.
 // 'value' can only hold one value. If you want to keep something else,
diff --git a/crates/lune-std-ffi/src/ffi/ffi_box.rs b/crates/lune-std-ffi/src/ffi/ffi_box.rs
index 9eb892b..f31a825 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_box.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_box.rs
@@ -1,5 +1,22 @@
 #![allow(clippy::cargo_common_metadata)]
 
+use std::boxed::Box;
+use std::sync::LazyLock;
+
+use mlua::prelude::*;
+
+use super::association_names::REF_INNER;
+use super::ffi_association::set_association;
+use super::ffi_ref::{FfiRef, FfiRefBounds, FfiRefFlag, FfiRefFlagList};
+
+static BOX_REF_FLAGS: LazyLock<FfiRefFlagList> = LazyLock::new(|| {
+    FfiRefFlagList::new(&[
+        FfiRefFlag::Offsetable,
+        FfiRefFlag::Readable,
+        FfiRefFlag::Writable,
+    ])
+});
+
 // It is an untyped, sized memory area that Lua can manage.
 // This area is safe within Lua. Operations have their boundaries checked.
 // It is basically intended to implement passing a pointed space to the outside.
@@ -9,15 +26,6 @@
 // rather, it creates more heap space, so it should be used appropriately
 // where necessary.
 
-use std::boxed::Box;
-
-use mlua::prelude::*;
-
-use super::association_names::REF_INNER;
-use super::ffi_association::set_association;
-use super::ffi_bounds::FfiRefBounds;
-use super::ffi_ref::FfiRef;
-
 pub struct FfiBox(Box<[u8]>);
 
 impl FfiBox {
@@ -73,7 +81,8 @@ impl FfiBox {
         // To deref a box space is to allow lua to read any space,
         // which has security issues and is ultimately dangerous.
         // Therefore, box:ref():deref() is not allowed.
-        let luaref = lua.create_userdata(FfiRef::new(ptr.cast(), false, Some(bounds)))?;
+        let luaref =
+            lua.create_userdata(FfiRef::new(ptr.cast(), (*BOX_REF_FLAGS).clone(), bounds))?;
 
         // Makes box alive longer then ref
         set_association(lua, REF_INNER, &luaref, &this)?;
diff --git a/crates/lune-std-ffi/src/ffi/ffi_helper.rs b/crates/lune-std-ffi/src/ffi/ffi_helper.rs
index 00605e7..26be508 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_helper.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_helper.rs
@@ -34,3 +34,23 @@ pub unsafe fn get_ptr_from_userdata(
 
     Ok(ptr)
 }
+
+#[allow(unused)]
+pub mod bit_mask {
+    pub const U8_MASK1: u8 = 1;
+    pub const U8_MASK2: u8 = 2;
+    pub const U8_MASK3: u8 = 4;
+    pub const U8_MASK4: u8 = 8;
+    pub const U8_MASK5: u8 = 16;
+    pub const U8_MASK6: u8 = 32;
+    pub const U8_MASK7: u8 = 64;
+    pub const U8_MASK8: u8 = 128;
+
+    macro_rules! U8_TEST {
+        ($val:expr, $mask:ident) => {
+            ($val & $mask != 0)
+        };
+    }
+
+    pub(crate) use U8_TEST;
+}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_lib.rs b/crates/lune-std-ffi/src/ffi/ffi_lib.rs
index a4a657f..6e393da 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_lib.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_lib.rs
@@ -1,10 +1,20 @@
 use std::ffi::c_void;
+use std::sync::LazyLock;
 
 use dlopen2::symbor::Library;
 use mlua::prelude::*;
 
 use super::ffi_association::set_association;
-use super::ffi_ref::FfiRef;
+use super::ffi_ref::{FfiRef, FfiRefFlag, FfiRefFlagList, UNSIZED_BOUNDS};
+
+static LIB_REF_FLAGS: LazyLock<FfiRefFlagList> = LazyLock::new(|| {
+    FfiRefFlagList::new(&[
+        FfiRefFlag::Offsetable,
+        FfiRefFlag::Readable,
+        FfiRefFlag::Dereferenceable,
+        FfiRefFlag::Function,
+    ])
+});
 
 pub struct FfiLib(Library);
 
@@ -39,7 +49,11 @@ impl FfiLib {
                 .map_err(|err| LuaError::external(format!("{err}")))?
         };
 
-        let luasym = lua.create_userdata(FfiRef::new((*sym).cast(), true, None))?;
+        let luasym = lua.create_userdata(FfiRef::new(
+            (*sym).cast(),
+            (*LIB_REF_FLAGS).clone(),
+            UNSIZED_BOUNDS,
+        ))?;
 
         set_association(lua, SYM_INNER, &luasym, &this)?;
 
diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs
new file mode 100644
index 0000000..50bd651
--- /dev/null
+++ b/crates/lune-std-ffi/src/ffi/ffi_native/cast.rs
@@ -0,0 +1,24 @@
+#![allow(clippy::cargo_common_metadata)]
+
+use mlua::prelude::*;
+use num::cast::AsPrimitive;
+
+use super::super::ffi_helper::get_ptr_from_userdata;
+
+pub trait NativeCast {
+    // Cast T as U
+    fn cast_num<T, U>(&self, from: &LuaAnyUserData, into: &LuaAnyUserData) -> LuaResult<()>
+    where
+        T: AsPrimitive<U>,
+        U: 'static + Copy,
+    {
+        let from_ptr = unsafe { get_ptr_from_userdata(from, None)?.cast::<T>() };
+        let into_ptr = unsafe { get_ptr_from_userdata(into, None)?.cast::<U>() };
+
+        unsafe {
+            *into_ptr = (*from_ptr).as_();
+        }
+
+        Ok(())
+    }
+}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs
new file mode 100644
index 0000000..e3b5d19
--- /dev/null
+++ b/crates/lune-std-ffi/src/ffi/ffi_native/convert.rs
@@ -0,0 +1,52 @@
+#![allow(clippy::cargo_common_metadata)]
+
+use mlua::prelude::*;
+
+use super::super::ffi_helper::get_ptr_from_userdata;
+
+// Handle native data, provide type conversion between luavalue and native types
+pub trait NativeConvert {
+    // Convert luavalue into data, then write into ptr
+    fn luavalue_into_ptr<'lua>(
+        &self,
+        this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        value: LuaValue<'lua>,
+        ptr: *mut (),
+    ) -> LuaResult<()>;
+
+    // Read data from ptr, then convert into luavalue
+    fn ptr_into_luavalue<'lua>(
+        &self,
+        this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        ptr: *mut (),
+    ) -> LuaResult<LuaValue<'lua>>;
+
+    // Read data from userdata (such as box or ref) and convert it into luavalue
+    unsafe fn read_userdata<'lua>(
+        &self,
+        this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        userdata: &LuaAnyUserData<'lua>,
+        offset: Option<isize>,
+    ) -> LuaResult<LuaValue<'lua>> {
+        let ptr = unsafe { get_ptr_from_userdata(userdata, offset)? };
+        let value = Self::ptr_into_luavalue(self, this, lua, ptr)?;
+        Ok(value)
+    }
+
+    // Write data into userdata (such as box or ref) from luavalue
+    unsafe fn write_userdata<'lua>(
+        &self,
+        this: &LuaAnyUserData<'lua>,
+        lua: &'lua Lua,
+        luavalue: LuaValue<'lua>,
+        userdata: LuaAnyUserData<'lua>,
+        offset: Option<isize>,
+    ) -> LuaResult<()> {
+        let ptr = unsafe { get_ptr_from_userdata(&userdata, offset)? };
+        Self::luavalue_into_ptr(self, this, lua, luavalue, ptr)?;
+        Ok(())
+    }
+}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs
new file mode 100644
index 0000000..16490b5
--- /dev/null
+++ b/crates/lune-std-ffi/src/ffi/ffi_native/mod.rs
@@ -0,0 +1,5 @@
+mod cast;
+mod convert;
+
+pub use self::cast::NativeCast;
+pub use self::convert::NativeConvert;
diff --git a/crates/lune-std-ffi/src/ffi/ffi_platform.rs b/crates/lune-std-ffi/src/ffi/ffi_platform.rs
deleted file mode 100644
index 30600d2..0000000
--- a/crates/lune-std-ffi/src/ffi/ffi_platform.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use core::ffi::c_char;
-use std::vec::Vec;
-
-pub const CHAR_IS_SIGNED: bool = c_char::MIN as u8 != u8::MIN;
-
-pub fn get_platform_value() -> Vec<(&'static str, &'static str)> {
-    vec![(
-        "char_variant",
-        if CHAR_IS_SIGNED { "schar" } else { "uchar" },
-    )]
-}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs
similarity index 58%
rename from crates/lune-std-ffi/src/ffi/ffi_bounds.rs
rename to crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs
index 5c73bb3..89c7f21 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_bounds.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_ref/bounds.rs
@@ -1,24 +1,36 @@
 // Memory range for ref or box data. For boundary checking
 pub struct FfiRefBounds {
     // Indicates how much data is above the pointer
-    pub(crate) high: usize,
+    pub(crate) above: usize,
     // Indicates how much data is below the pointer
-    pub(crate) low: usize,
+    pub(crate) below: usize,
 }
 
+pub const UNSIZED_BOUNDS: FfiRefBounds = FfiRefBounds {
+    above: usize::MAX,
+    below: usize::MAX,
+};
+
 impl FfiRefBounds {
-    pub fn new(high: usize, low: usize) -> Self {
-        Self { high, low }
+    pub fn new(above: usize, below: usize) -> Self {
+        Self { above, below }
+    }
+
+    pub fn is_unsized(&self) -> bool {
+        self.above == usize::MAX && self.below == usize::MAX
     }
 
     // Check boundary
     pub fn check(&self, offset: isize) -> bool {
+        if self.is_unsized() {
+            return true;
+        }
         let sign = offset.signum();
         let offset_abs = offset.unsigned_abs();
         if sign == -1 {
-            self.high >= offset_abs
+            self.above >= offset_abs
         } else if sign == 1 {
-            self.low >= offset_abs
+            self.below >= offset_abs
         } else {
             // sign == 0
             true
@@ -27,13 +39,16 @@ impl FfiRefBounds {
 
     // Check boundary
     pub fn check_sized(&self, offset: isize, size: usize) -> bool {
+        if self.is_unsized() {
+            return true;
+        }
         let end = offset + (size as isize) - 1;
         let sign = end.signum();
         let end_abs = end.unsigned_abs();
         if sign == -1 {
-            self.high >= end_abs
+            self.above >= end_abs
         } else if sign == 1 {
-            self.low >= end_abs
+            self.below >= end_abs
         } else {
             // sign == 0
             true
@@ -47,21 +62,24 @@ impl FfiRefBounds {
         let offset_abs = offset.unsigned_abs();
 
         let high: usize = if sign == -1 {
-            self.high - offset_abs
+            self.above - offset_abs
         } else if sign == 1 {
-            self.high + offset_abs
+            self.above + offset_abs
         } else {
-            self.high
+            self.above
         };
 
         let low: usize = if sign == -1 {
-            self.low + offset_abs
+            self.below + offset_abs
         } else if sign == 1 {
-            self.low - offset_abs
+            self.below - offset_abs
         } else {
-            self.low
+            self.below
         };
 
-        Self { high, low }
+        Self {
+            above: high,
+            below: low,
+        }
     }
 }
diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs
new file mode 100644
index 0000000..faf969e
--- /dev/null
+++ b/crates/lune-std-ffi/src/ffi/ffi_ref/flags.rs
@@ -0,0 +1,71 @@
+use super::super::ffi_helper::bit_mask::*;
+
+pub enum FfiRefFlag {
+    Dereferenceable,
+    Readable,
+    Writable,
+    Offsetable,
+    Function,
+}
+impl FfiRefFlag {
+    pub const fn value(&self) -> u8 {
+        match self {
+            Self::Dereferenceable => U8_MASK1,
+            Self::Readable => U8_MASK2,
+            Self::Writable => U8_MASK3,
+            Self::Offsetable => U8_MASK4,
+            Self::Function => U8_MASK5,
+        }
+    }
+}
+
+pub struct FfiRefFlagList(u8);
+#[allow(unused)]
+impl FfiRefFlagList {
+    pub fn zero() -> Self {
+        Self(0)
+    }
+    pub fn new(flags: &[FfiRefFlag]) -> Self {
+        let mut value = 0;
+        for i in flags {
+            value |= i.value();
+        }
+        Self(value)
+    }
+    fn set(&mut self, value: bool, mask: u8) {
+        if value {
+            self.0 |= mask;
+        } else {
+            self.0 &= !mask;
+        }
+    }
+    pub fn is_dereferenceable(&self) -> bool {
+        U8_TEST!(self.0, U8_MASK1)
+    }
+    pub fn set_dereferenceable(&mut self, value: bool) {
+        self.set(value, U8_MASK1);
+    }
+    pub fn is_readable(&self) -> bool {
+        U8_TEST!(self.0, U8_MASK2)
+    }
+    pub fn set_readable(&mut self, value: bool) {
+        self.set(value, U8_MASK2);
+    }
+    pub fn is_writable(&self) -> bool {
+        U8_TEST!(self.0, U8_MASK3)
+    }
+    pub fn set_writable(&mut self, value: bool) {
+        self.set(value, U8_MASK2);
+    }
+    pub fn is_offsetable(&self) -> bool {
+        U8_TEST!(self.0, U8_MASK4)
+    }
+    pub fn set_offsetable(&mut self, value: bool) {
+        self.set(value, U8_MASK2);
+    }
+}
+impl Clone for FfiRefFlagList {
+    fn clone(&self) -> Self {
+        Self(self.0)
+    }
+}
diff --git a/crates/lune-std-ffi/src/ffi/ffi_ref.rs b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs
similarity index 50%
rename from crates/lune-std-ffi/src/ffi/ffi_ref.rs
rename to crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs
index 8700e72..19aa6f4 100644
--- a/crates/lune-std-ffi/src/ffi/ffi_ref.rs
+++ b/crates/lune-std-ffi/src/ffi/ffi_ref/mod.rs
@@ -4,7 +4,12 @@ use mlua::prelude::*;
 
 use super::association_names::REF_INNER;
 use super::ffi_association::{get_association, set_association};
-use super::ffi_bounds::FfiRefBounds;
+
+mod bounds;
+mod flags;
+
+pub use self::bounds::{FfiRefBounds, UNSIZED_BOUNDS};
+pub use self::flags::{FfiRefFlag, FfiRefFlagList};
 
 // A referenced space. It is possible to read and write through types.
 // This operation is not safe. This may cause a memory error in Lua
@@ -16,16 +21,16 @@ use super::ffi_bounds::FfiRefBounds;
 
 pub struct FfiRef {
     ptr: *mut (),
-    dereferenceable: bool,
-    range: Option<FfiRefBounds>,
+    flags: FfiRefFlagList,
+    boundary: FfiRefBounds,
 }
 
 impl FfiRef {
-    pub fn new(ptr: *mut (), dereferenceable: bool, range: Option<FfiRefBounds>) -> Self {
+    pub fn new(ptr: *mut (), flags: FfiRefFlagList, range: FfiRefBounds) -> Self {
         Self {
             ptr,
-            dereferenceable,
-            range,
+            flags,
+            boundary: range,
         }
     }
 
@@ -35,14 +40,19 @@ impl FfiRef {
         this: LuaAnyUserData<'lua>,
     ) -> LuaResult<LuaAnyUserData<'lua>> {
         let target = this.borrow::<FfiRef>()?;
+        let mut flags = target.flags.clone();
+
+        // FIXME:
+        // We cannot dereference ref which created by lua, in lua
+        flags.set_dereferenceable(false);
 
         let luaref = lua.create_userdata(FfiRef::new(
             ptr::from_ref(&target.ptr) as *mut (),
-            true,
-            Some(FfiRefBounds {
-                low: 0,
-                high: size_of::<usize>(),
-            }),
+            flags,
+            FfiRefBounds {
+                below: 0,
+                above: size_of::<usize>(),
+            },
         ))?;
 
         // If the ref holds a box, make sure the new ref also holds the box by holding ref
@@ -55,26 +65,51 @@ impl FfiRef {
         self.ptr
     }
 
-    pub unsafe fn deref(&self) -> Self {
-        // FIXME
-        Self::new(*self.ptr.cast::<*mut ()>(), true, None)
+    pub unsafe fn deref(&self) -> LuaResult<Self> {
+        self.flags
+            .is_dereferenceable()
+            .then_some(())
+            .ok_or(LuaError::external("This pointer is not dereferenceable."))?;
+
+        self.boundary
+            .check_sized(0, size_of::<usize>())
+            .then_some(())
+            .ok_or(LuaError::external(
+                "Offset is out of bounds. Dereferencing pointer requires size of usize",
+            ))?;
+
+        // FIXME flags
+        Ok(Self::new(
+            *self.ptr.cast::<*mut ()>(),
+            self.flags.clone(),
+            UNSIZED_BOUNDS,
+        ))
+    }
+
+    pub fn is_nullptr(&self) -> bool {
+        self.ptr as usize == 0
     }
 
     pub unsafe fn offset(&self, offset: isize) -> LuaResult<Self> {
-        if let Some(ref t) = self.range {
-            if !t.check(offset) {
-                return Err(LuaError::external(format!(
-                    "Offset is out of bounds. high: {}, low: {}. offset got {}",
-                    t.high, t.low, offset
-                )));
-            }
-        }
-        let range = self.range.as_ref().map(|t| t.offset(offset));
+        self.flags
+            .is_offsetable()
+            .then_some(())
+            .ok_or(LuaError::external("This pointer is not offsetable."))?;
+
+        // Check boundary, if exceed, return error
+        self.boundary.check(offset).then_some(()).ok_or_else(|| {
+            LuaError::external(format!(
+                "Offset is out of bounds. high: {}, low: {}. offset got {}",
+                self.boundary.above, self.boundary.below, offset
+            ))
+        })?;
+
+        let boundary = self.boundary.offset(offset);
 
         Ok(Self::new(
             self.ptr.byte_offset(offset),
-            self.dereferenceable,
-            range,
+            self.flags.clone(),
+            boundary,
         ))
     }
 }
@@ -84,7 +119,7 @@ impl LuaUserData for FfiRef {
         methods.add_function("deref", |lua, this: LuaAnyUserData| {
             let inner = get_association(lua, REF_INNER, &this)?;
             let ffiref = this.borrow::<FfiRef>()?;
-            let result = lua.create_userdata(unsafe { ffiref.deref() })?;
+            let result = lua.create_userdata(unsafe { ffiref.deref()? })?;
 
             if let Some(t) = inner {
                 // if let Some(u) = get_association(lua, regname, value) {}
@@ -108,5 +143,18 @@ impl LuaUserData for FfiRef {
             let ffiref = FfiRef::luaref(lua, this)?;
             Ok(ffiref)
         });
+        methods.add_method("isNullptr", |_, this, ()| Ok(this.is_nullptr()));
     }
 }
+
+pub fn create_nullptr(lua: &Lua) -> LuaResult<LuaAnyUserData> {
+    // https://en.cppreference.com/w/cpp/types/nullptr_t
+    lua.create_userdata(FfiRef::new(
+        ptr::null_mut::<()>().cast(),
+        FfiRefFlagList::zero(),
+        // usize::MAX means that nullptr is can be 'any' pointer type
+        // We check size of inner data. give ffi.box(1):ref() as argument which typed as i32:ptr() will fail,
+        // throw lua error
+        UNSIZED_BOUNDS,
+    ))
+}
diff --git a/crates/lune-std-ffi/src/ffi/mod.rs b/crates/lune-std-ffi/src/ffi/mod.rs
index dd36905..c13f88a 100644
--- a/crates/lune-std-ffi/src/ffi/mod.rs
+++ b/crates/lune-std-ffi/src/ffi/mod.rs
@@ -1,11 +1,10 @@
-pub(super) mod ffi_association;
-pub(super) mod ffi_bounds;
-pub(super) mod ffi_box;
-pub(super) mod ffi_helper;
-pub(super) mod ffi_lib;
-pub(super) mod ffi_platform;
-pub(super) mod ffi_raw;
-pub(super) mod ffi_ref;
+pub mod ffi_association;
+pub mod ffi_box;
+pub mod ffi_helper;
+pub mod ffi_lib;
+pub mod ffi_native;
+pub mod ffi_raw;
+pub mod ffi_ref;
 
 // Named registry table names
 mod association_names {
diff --git a/crates/lune-std-ffi/src/lib.rs b/crates/lune-std-ffi/src/lib.rs
index 355cf3b..36549a9 100644
--- a/crates/lune-std-ffi/src/lib.rs
+++ b/crates/lune-std-ffi/src/lib.rs
@@ -3,14 +3,12 @@
 use lune_utils::TableBuilder;
 use mlua::prelude::*;
 
+use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_c_types, create_all_types};
+use crate::ffi::{ffi_box::FfiBox, ffi_lib::FfiLib, ffi_ref::create_nullptr};
+
 mod c;
 mod ffi;
 
-use crate::c::{c_fn::CFn, c_struct::CStruct, create_all_types};
-use crate::ffi::{
-    ffi_association::get_table, ffi_box::FfiBox, ffi_lib::FfiLib, ffi_platform::get_platform_value,
-};
-
 /**
     Creates the `ffi` standard library module.
 
@@ -19,10 +17,10 @@ use crate::ffi::{
     Errors when out of memory.
 */
 pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
-    let ctypes = create_all_types(lua)?;
     let result = TableBuilder::new(lua)?
-        .with_values(ctypes)?
-        .with_values(get_platform_value())?
+        .with_values(create_all_types(lua)?)?
+        .with_values(create_all_c_types(lua)?)?
+        .with_value("nullptr", create_nullptr(lua)?)?
         .with_function("box", |_, size: usize| Ok(FfiBox::new(size)))?
         // TODO: discuss about function name. matching with io.open is better?
         .with_function("dlopen", |_, name: String| {
@@ -40,7 +38,7 @@ pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
 
     #[cfg(debug_assertions)]
     let result = result.with_function("debug_associate", |lua, str: String| {
-        get_table(lua, str.as_ref())
+        crate::ffi::ffi_association::get_table(lua, str.as_ref())
     })?;
 
     result.build_readonly()
diff --git a/crates/lune-std-ffi/todo.md b/crates/lune-std-ffi/todo.md
deleted file mode 100644
index fbd8999..0000000
--- a/crates/lune-std-ffi/todo.md
+++ /dev/null
@@ -1,99 +0,0 @@
-- last thing to do
-- [ ] Add tests
-- [ ] Add docs
-- [ ] Typing
-
-pragma pack?
-
-# Raw
-
-- [ ] Raw:toRef()
-- [ ] Raw:toBox()
-- [ ] Raw:intoBox()
-- [ ] Raw:intoRef()
-
-# Box
-
-- [x] ffi.box(size)
-- [x] .size
-- [x] :zero()
-- [x] :ref(offset?=0) => ref
-- [x] tostring
-
-- [~] :copy(box,size?=-1,offset?=0)
-  - working on it
-
-# Ref (Unsafe)
-
-- [ ] high, low Boundaries
-- [ ] iter
-
-- [x] ref:deref() -> ref
-- [x] ref:offset(bytes) -> ref
-- [x] ref:ref() -> ref
-
-~~- [ ] ref:fromRef(size,offset?=0) ?? what is this~~
-~~- [ ] ref:fromBox(size,offset?=0) ?? what is this~~
-
-# Struct
-
-- [x] :offset(index)
-- [x] :ptr()
-- [x] .inner[n]
-- [!] .size
-- [ ] #
-- [x] tostring
-
-size, offset is strange. maybe related to cif state.
-
-# Type
-
-- [ ] :toBox(luavalue)
-
-Very stupid idea.
-from(box|ref|raw, offset) is better idea i think.
-
-- [ ] :fromBox(box,offset?=0)
-- [ ] :intoBox(luavalue,box,offset?=0)
-- [ ] :fromRef(ref,offset?=0)
-- [ ] :intoRef(luavalue,ref,offset?=0)
-- [ ] :fromRaw(raw,offset?=0)
-
-- [ ] :castBox(box,type) TODO
-- [ ]
-
-- [ ] :sum
-- [ ] :mul
-- [ ] :sub
-
-## subtype
-
-- [x] :ptr() -> Ptr
-- [~] :arr(len) -> Arr
-- [x] .size
-
-# Ptr
-
-- [x] .inner
-- [x] .size
-- [x] :ptr()
-- [~] :arr()
-
-## Arr
-
-## Void
-
-`ffi.void`
-
-Zero sized type.
-
-## Fn
-
-Prototype type of some function. converts lua function into native function pointer or native function pointer into lua function.
-
-`ffi.fn({ type }, type) -> fn`
-
-:toLua( ref ) -> luafunction
-:toBox( luafunction ) -> ref
-
-> TODO: rust, and another ABI support