use super::*;
unsafe extern "C" {
fn proto2_rust_thunk_UntypedMapIterator_increment(iter: &mut UntypedMapIterator);
pub fn proto2_rust_map_new(key_prototype: FfiMapValue, value_prototype: FfiMapValue) -> RawMap;
pub fn proto2_rust_map_free(m: RawMap);
pub fn proto2_rust_map_clear(m: RawMap);
pub fn proto2_rust_map_size(m: RawMap) -> usize;
pub fn proto2_rust_map_iter(m: RawMap) -> UntypedMapIterator;
}
#[doc(hidden)]
pub trait MapKey: Proxied + FfiMapKey + CppMapTypeConversions + SealedInternal {}
#[derive(Debug)]
#[doc(hidden)]
pub struct InnerMap {
pub(crate) raw: RawMap,
}
impl InnerMap {
pub fn new(raw: RawMap) -> Self {
Self { raw }
}
pub fn as_mut(&mut self) -> InnerMapMut<'_> {
InnerMapMut { raw: self.raw, _phantom: PhantomData }
}
}
#[derive(Clone, Copy, Debug)]
#[doc(hidden)]
pub struct InnerMapMut<'msg> {
pub(crate) raw: RawMap,
_phantom: PhantomData<&'msg ()>,
}
#[doc(hidden)]
impl<'msg> InnerMapMut<'msg> {
pub fn new(raw: RawMap) -> Self {
InnerMapMut { raw, _phantom: PhantomData }
}
pub fn as_raw(&self) -> RawMap {
self.raw
}
}
#[repr(C)]
#[doc(hidden)]
pub struct UntypedMapIterator {
node: *mut c_void,
map: *const c_void,
bucket_index: u32,
}
impl UntypedMapIterator {
fn at_end(&self) -> bool {
self.node.is_null()
}
#[inline(always)]
pub unsafe fn next_unchecked<'a, K, V, FfiKey, FfiValue>(
&mut self,
iter_get_thunk: unsafe fn(
iter: &mut UntypedMapIterator,
key: *mut FfiKey,
value: *mut FfiValue,
),
from_ffi_key: impl FnOnce(FfiKey) -> View<'a, K>,
from_ffi_value: impl FnOnce(FfiValue) -> View<'a, V>,
) -> Option<(View<'a, K>, View<'a, V>)>
where
K: MapKey + 'a,
V: MapValue + 'a,
{
if self.at_end() {
return None;
}
let mut ffi_key = MaybeUninit::uninit();
let mut ffi_value = MaybeUninit::uninit();
unsafe { (iter_get_thunk)(self, ffi_key.as_mut_ptr(), ffi_value.as_mut_ptr()) }
unsafe { proto2_rust_thunk_UntypedMapIterator_increment(self) }
unsafe {
Some((from_ffi_key(ffi_key.assume_init()), from_ffi_value(ffi_value.assume_init())))
}
}
}
#[doc(hidden)]
#[repr(u8)]
#[derive(Debug, PartialEq)]
pub enum FfiMapValueTag {
Bool,
U32,
U64,
F32,
F64,
String,
Message,
}
#[doc(hidden)]
#[repr(C)]
pub union FfiMapValueUnion {
pub b: bool,
pub u: u32,
pub uu: u64,
pub f: f32,
pub ff: f64,
pub s: Option<CppStdString>,
pub m: RawMessage,
}
#[doc(hidden)]
#[repr(C)]
pub struct FfiMapValue {
pub tag: FfiMapValueTag,
pub val: FfiMapValueUnion,
}
impl FfiMapValue {
fn make_bool(b: bool) -> Self {
FfiMapValue { tag: FfiMapValueTag::Bool, val: FfiMapValueUnion { b } }
}
pub fn make_u32(u: u32) -> Self {
FfiMapValue { tag: FfiMapValueTag::U32, val: FfiMapValueUnion { u } }
}
fn make_u64(uu: u64) -> Self {
FfiMapValue { tag: FfiMapValueTag::U64, val: FfiMapValueUnion { uu } }
}
pub fn make_f32(f: f32) -> Self {
FfiMapValue { tag: FfiMapValueTag::F32, val: FfiMapValueUnion { f } }
}
fn make_f64(ff: f64) -> Self {
FfiMapValue { tag: FfiMapValueTag::F64, val: FfiMapValueUnion { ff } }
}
fn make_string(s: CppStdString) -> Self {
FfiMapValue { tag: FfiMapValueTag::String, val: FfiMapValueUnion { s: Some(s) } }
}
pub fn make_message(m: RawMessage) -> Self {
FfiMapValue { tag: FfiMapValueTag::Message, val: FfiMapValueUnion { m } }
}
}
pub trait CppMapTypeConversions: Proxied {
fn get_prototype() -> FfiMapValue;
fn to_map_value(self) -> FfiMapValue;
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self>;
#[allow(unused_variables)]
unsafe fn mut_from_map_value<'a>(value: FfiMapValue) -> Mut<'a, Self>
where
Self: Message,
{
panic!("mut_from_map_value is only implemented for messages")
}
}
impl CppMapTypeConversions for u32 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_u32(0)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_u32(self)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::U32);
unsafe { value.val.u }
}
}
impl CppMapTypeConversions for i32 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_u32(0)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_u32(self as u32)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::U32);
unsafe { value.val.u as i32 }
}
}
impl CppMapTypeConversions for u64 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_u64(0)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_u64(self)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::U64);
unsafe { value.val.uu }
}
}
impl CppMapTypeConversions for i64 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_u64(0)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_u64(self as u64)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::U64);
unsafe { value.val.uu as i64 }
}
}
impl CppMapTypeConversions for f32 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_f32(0f32)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_f32(self)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::F32);
unsafe { value.val.f }
}
}
impl CppMapTypeConversions for f64 {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_f64(0.0)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_f64(self)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::F64);
unsafe { value.val.ff }
}
}
impl CppMapTypeConversions for bool {
fn get_prototype() -> FfiMapValue {
FfiMapValue::make_bool(false)
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_bool(self)
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> View<'a, Self> {
debug_assert_eq!(value.tag, FfiMapValueTag::Bool);
unsafe { value.val.b }
}
}
impl CppMapTypeConversions for ProtoString {
fn get_prototype() -> FfiMapValue {
FfiMapValue { tag: FfiMapValueTag::String, val: FfiMapValueUnion { s: None } }
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_string(protostr_into_cppstdstring(self))
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> &'a ProtoStr {
debug_assert_eq!(value.tag, FfiMapValueTag::String);
unsafe { ptrlen_to_str(proto2_rust_cpp_string_to_view(value.val.s.unwrap())) }
}
}
impl CppMapTypeConversions for ProtoBytes {
fn get_prototype() -> FfiMapValue {
FfiMapValue { tag: FfiMapValueTag::String, val: FfiMapValueUnion { s: None } }
}
fn to_map_value(self) -> FfiMapValue {
FfiMapValue::make_string(protobytes_into_cppstdstring(self))
}
unsafe fn from_map_value<'a>(value: FfiMapValue) -> &'a [u8] {
debug_assert_eq!(value.tag, FfiMapValueTag::String);
unsafe { proto2_rust_cpp_string_to_view(value.val.s.unwrap()).as_ref() }
}
}
#[doc(hidden)]
pub trait FfiMapKey
where
Self: Proxied,
{
type FfiKey;
fn to_view<'a>(key: Self::FfiKey) -> View<'a, Self>;
unsafe fn insert(m: RawMap, key: View<'_, Self>, value: FfiMapValue) -> bool;
unsafe fn get(m: RawMap, key: View<'_, Self>, value: *mut FfiMapValue) -> bool;
unsafe fn iter_get(
iter: &mut UntypedMapIterator,
key: *mut Self::FfiKey,
value: *mut FfiMapValue,
);
unsafe fn remove(m: RawMap, key: View<'_, Self>) -> bool;
}
macro_rules! generate_map_key_impl {
( $($key:ty, $mutable_ffi_key:ty, $to_ffi:expr, $from_ffi:expr;)* ) => {
paste! {
$(
impl FfiMapKey for $key {
type FfiKey = $mutable_ffi_key;
#[inline]
fn to_view<'a>(key: Self::FfiKey) -> View<'a, Self> {
$from_ffi(key)
}
#[inline]
unsafe fn insert(
m: RawMap,
key: View<'_, Self>,
value: FfiMapValue,
) -> bool {
unsafe { [< proto2_rust_map_insert_ $key >](m, $to_ffi(key), value) }
}
#[inline]
unsafe fn get(
m: RawMap,
key: View<'_, Self>,
value: *mut FfiMapValue,
) -> bool {
unsafe { [< proto2_rust_map_get_ $key >](m, $to_ffi(key), value) }
}
#[inline]
unsafe fn iter_get(
iter: &mut UntypedMapIterator,
key: *mut Self::FfiKey,
value: *mut FfiMapValue,
) {
unsafe { [< proto2_rust_map_iter_get_ $key >](iter, key, value) }
}
#[inline]
unsafe fn remove(m: RawMap, key: View<'_, Self>) -> bool {
unsafe { [< proto2_rust_map_remove_ $key >](m, $to_ffi(key)) }
}
}
)*
}
}
}
generate_map_key_impl!(
bool, bool, identity, identity;
i32, i32, identity, identity;
u32, u32, identity, identity;
i64, i64, identity, identity;
u64, u64, identity, identity;
ProtoString, PtrAndLen, str_to_ptrlen, ptrlen_to_str;
);
impl<Value> MapValue for Value
where
Value: Singular + CppMapTypeConversions,
{
fn map_new<Key: MapKey>(_private: Private) -> Map<Key, Self> {
unsafe {
Map::from_inner(
Private,
InnerMap::new(proto2_rust_map_new(Key::get_prototype(), Value::get_prototype())),
)
}
}
unsafe fn map_free<Key: MapKey>(_private: Private, map: &mut Map<Key, Self>) {
unsafe {
proto2_rust_map_free(map.as_raw(Private));
}
}
fn map_clear<Key: MapKey>(_private: Private, mut map: MapMut<Key, Self>) {
unsafe {
proto2_rust_map_clear(map.as_raw(Private));
}
}
fn map_len<Key: MapKey>(_private: Private, map: MapView<Key, Self>) -> usize {
unsafe { proto2_rust_map_size(map.as_raw(Private)) }
}
fn map_insert<Key: MapKey>(
_private: Private,
mut map: MapMut<Key, Self>,
key: View<'_, Key>,
value: impl IntoProxied<Self>,
) -> bool {
unsafe { Key::insert(map.as_raw(Private), key, value.into_proxied(Private).to_map_value()) }
}
fn map_get<'a, Key: MapKey>(
_private: Private,
map: MapView<'a, Key, Self>,
key: View<'_, Key>,
) -> Option<View<'a, Self>> {
let mut value = std::mem::MaybeUninit::uninit();
let found = unsafe { Key::get(map.as_raw(Private), key, value.as_mut_ptr()) };
if !found {
return None;
}
unsafe { Some(Self::from_map_value(value.assume_init())) }
}
fn map_get_mut<'a, Key: MapKey>(
_private: Private,
mut map: MapMut<'a, Key, Self>,
key: View<'_, Key>,
) -> Option<Mut<'a, Self>>
where
Value: Message,
{
let mut value = std::mem::MaybeUninit::uninit();
let found = unsafe { Key::get(map.as_raw(Private), key, value.as_mut_ptr()) };
if !found {
return None;
}
unsafe { Some(Self::mut_from_map_value(value.assume_init())) }
}
fn map_remove<Key: MapKey>(
_private: Private,
mut map: MapMut<Key, Self>,
key: View<'_, Key>,
) -> bool {
unsafe { Key::remove(map.as_raw(Private), key) }
}
fn map_iter<Key: MapKey>(_private: Private, map: MapView<Key, Self>) -> MapIter<Key, Self> {
unsafe { MapIter::from_raw(Private, proto2_rust_map_iter(map.as_raw(Private))) }
}
fn map_iter_next<'a, Key: MapKey>(
_private: Private,
iter: &mut MapIter<'a, Key, Self>,
) -> Option<(View<'a, Key>, View<'a, Self>)> {
unsafe {
iter.as_raw_mut(Private).next_unchecked::<Key, Self, _, _>(
|iter, key, value| Key::iter_get(iter, key, value),
|ffi_key| Key::to_view(ffi_key),
|value| Self::from_map_value(value),
)
}
}
}
macro_rules! impl_map_primitives {
(@impl $(($rust_type:ty, $cpp_type:ty) => [
$insert_thunk:ident,
$get_thunk:ident,
$iter_get_thunk:ident,
$remove_thunk:ident,
]),* $(,)?) => {
$(
unsafe extern "C" {
pub fn $insert_thunk(
m: RawMap,
key: $cpp_type,
value: FfiMapValue,
) -> bool;
pub fn $get_thunk(
m: RawMap,
key: $cpp_type,
value: *mut FfiMapValue,
) -> bool;
pub fn $iter_get_thunk(
iter: &mut UntypedMapIterator,
key: *mut $cpp_type,
value: *mut FfiMapValue,
);
pub fn $remove_thunk(m: RawMap, key: $cpp_type) -> bool;
}
)*
};
($($rust_type:ty, $cpp_type:ty;)* $(,)?) => {
paste!{
impl_map_primitives!(@impl $(
($rust_type, $cpp_type) => [
[< proto2_rust_map_insert_ $rust_type >],
[< proto2_rust_map_get_ $rust_type >],
[< proto2_rust_map_iter_get_ $rust_type >],
[< proto2_rust_map_remove_ $rust_type >],
],
)*);
}
};
}
impl_map_primitives!(
i32, i32;
u32, u32;
i64, i64;
u64, u64;
bool, bool;
ProtoString, PtrAndLen;
);