Skip to content

Commit 7a710de

Browse files
committed
Implement StaticReflect for AsmStr/AsmOption
Whoops! Can't believe I missed this :o Add a SimpleNonZeroPointer trait.
1 parent 3000980 commit 7a710de

File tree

4 files changed

+102
-16
lines changed

4 files changed

+102
-16
lines changed

src/builtins.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! These are mostly FFI-safe alternatives to the standard library
44
//! types.
55
use std::mem::MaybeUninit;
6-
use crate::StaticReflect;
6+
use crate::{StaticReflect, field_offset, TypeInfo};
77

88
/// A FFi-safe slice type (`&[T]`)
99
///
@@ -37,7 +37,21 @@ impl<T: StaticReflect> Clone for AsmSlice<T> {
3737
}
3838
}
3939
impl<T: StaticReflect> Copy for AsmSlice<T> {}
40+
impl<'a, T: 'a> From<&'a [T]> for AsmSlice<T> {
41+
#[inline]
42+
fn from(slice: &'a [T]) -> Self {
43+
AsmSlice { ptr: slice.as_ptr() as *mut _, len: slice.len() }
44+
}
45+
}
46+
unsafe impl<T: StaticReflect> StaticReflect for AsmSlice<T> {
47+
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Slice {
48+
element_type: &T::TYPE_INFO
49+
};
50+
}
4051

52+
/// Assuming there is no mutation of the underlying memory,
53+
/// this is safe to send between threads
54+
unsafe impl<T: Sync> Send for AsmSlice<T> {}
4155

4256
/// A FFI-safe UTF8 string.
4357
///
@@ -65,6 +79,14 @@ impl AsmStr {
6579
self.bytes.len
6680
}
6781
}
82+
unsafe impl StaticReflect for AsmStr {
83+
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Str;
84+
}
85+
impl<'a> From<&'a str> for AsmStr {
86+
fn from(s: &'a str) -> AsmStr {
87+
AsmStr { bytes: s.as_bytes().into() }
88+
}
89+
}
6890

6991
/// A FFI-safe alternative to Rust's [std::optional::Option].
7092
///
@@ -87,6 +109,23 @@ pub struct AsmOption<T> {
87109
present: bool,
88110
value: MaybeUninit<T>
89111
}
112+
impl AsmOption<()> {
113+
/// The offset of the 'present' field
114+
///
115+
/// This should be zero, regardless of the inner type
116+
#[inline]
117+
pub const fn present_field_offset() -> usize {
118+
assert!(field_offset!(AsmOption::<()>, present) == 0);
119+
0
120+
}
121+
/// The offset of the value field
122+
///
123+
/// This should be equal to the type's alignment
124+
#[inline]
125+
pub const fn value_field_offset(element_type: TypeInfo<'static>) -> usize {
126+
element_type.alignment()
127+
}
128+
}
90129
impl<T> AsmOption<T> {
91130
/// An option with no value
92131
#[inline]
@@ -123,3 +162,17 @@ impl<T> AsmOption<T> {
123162
self.present
124163
}
125164
}
165+
impl<T> From<Option<T>> for AsmOption<T> {
166+
fn from(o: Option<T>) -> AsmOption<T> {
167+
match o {
168+
None => AsmOption::none(),
169+
Some(v) => AsmOption::some(v)
170+
}
171+
}
172+
}
173+
unsafe impl<T: StaticReflect> StaticReflect for AsmOption<T> {
174+
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Optional(&T::TYPE_INFO);
175+
}
176+
177+
/// This is an owned value, so it's safe to send
178+
unsafe impl<T: Send> Send for AsmOption<T> {}

src/core.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Implementations of [StaticReflect] for core types (for `#![no_std]`)
22
use crate::StaticReflect;
33
use crate::types::{TypeInfo};
4+
use std::mem::{self, ManuallyDrop};
5+
use core::ptr::NonNull;
46

57
macro_rules! impl_primitive {
68
($target:ty => $info:expr) => {
@@ -31,6 +33,18 @@ impl_primitive!(bool => TypeInfo::Bool);
3133
impl_primitive!(f32 => TypeInfo::F32);
3234
impl_primitive!(f64 => TypeInfo::F64);
3335

36+
// Builtin support for the never type
37+
impl_primitive!(! => TypeInfo::Never);
38+
39+
40+
/// Support [StaticReflect] for [ManuallyDrop] by just representing the inner type
41+
unsafe impl<T: StaticReflect> StaticReflect for ManuallyDrop<T> {
42+
const TYPE_INFO: TypeInfo<'static> = {
43+
assert!(mem::size_of::<Self>() == mem::size_of::<T>());
44+
T::TYPE_INFO
45+
};
46+
}
47+
3448
/// A pointer
3549
///
3650
/// NOTE: The pointed-to value can be anything,
@@ -49,3 +63,18 @@ unsafe impl <T> StaticReflect for *mut T {
4963
unsafe impl <T> StaticReflect for *const T {
5064
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Pointer;
5165
}
66+
67+
/// A non-zero pointer type, where optional types
68+
/// are guaranteed to use the nullable representation
69+
///
70+
/// If `T: SimpleNonZeroPointer` -> `sizeof(Option<T>) == sizeof(T) && repr(Option<T>) == repr(T)`
71+
pub unsafe trait SimpleNonZeroPointer: StaticReflect {}
72+
73+
unsafe impl <T> SimpleNonZeroPointer for NonNull<T> {}
74+
unsafe impl <T> StaticReflect for NonNull<T> {
75+
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Pointer;
76+
}
77+
78+
unsafe impl <T: SimpleNonZeroPointer> StaticReflect for Option<T> {
79+
const TYPE_INFO: TypeInfo<'static> = TypeInfo::Pointer;
80+
}

src/lib.rs

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
#![feature(
1414
const_fn, // We rely on const eval :(
1515
const_panic, const_option, // We use Option::unwrap
16+
// Used for field_offset macro
17+
const_raw_ptr_deref,
18+
const_raw_ptr_to_usize_cast,
1619
)]
1720
#![cfg_attr(feature = "never", feature(never_type))]
1821

22+
mod macros;
1923
#[cfg(feature = "builtins")]
2024
pub mod builtins;
2125
pub mod types;
@@ -25,21 +29,6 @@ mod core;
2529

2630
use crate::types::TypeInfo;
2731

28-
/// Get the integer offset of the specified field
29-
#[macro_export]
30-
macro_rules! field_offset {
31-
($target:path, $($field:ident),+) => {
32-
unsafe {
33-
/*
34-
* I'm going to assume the dereference is safe,
35-
* because of the presense of '(*uninit.as_mut_ptr()).field'
36-
* in the documentation for std::ptr::addr_of_mut
37-
*/
38-
(std::ptr::addr_of!((*(1 as *mut $target))$(.$field)*) as usize) - 1
39-
}
40-
}
41-
}
42-
4332
/// The trait for types whose information can be accessed via static reflection.
4433
///
4534
/// In order to proper access any fields,

src/macros.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
/// Get the integer offset of the specified field
3+
#[macro_export]
4+
macro_rules! field_offset {
5+
($target:path, $($field:ident),+) => {
6+
unsafe {
7+
/*
8+
* I'm going to assume the dereference is safe,
9+
* because of the presense of '(*uninit.as_mut_ptr()).field'
10+
* in the documentation for std::ptr::addr_of_mut
11+
*/
12+
(std::ptr::addr_of!((*(1 as *mut $target))$(.$field)*) as usize) - 1
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)