use alloc::string::String;
use alloc::vec::Vec;
use buffa::bytes::Bytes;
use buffa::{EnumValue, Enumeration, MapView, RepeatedView};
use super::value::{MapKey, MapKeyRef, ReflectList, ReflectMap, Value, ValueRef};
#[diagnostic::on_unimplemented(
message = "`{Self}` does not implement `ReflectElement`, which vtable-mode reflection requires on repeated-field and map-value element types",
note = "if `{Self}` comes from another buffa-generated crate via an extern path (well-known types resolve to `buffa-types` by default), enable that crate's reflection feature, e.g. `buffa-types = {{ version = \"...\", features = [\"reflect\"] }}`",
note = "if `{Self}` is a message generated in this crate, enable reflection in its `build.rs` config — either reflection mode emits this impl",
note = "for a non-default `string_type` element (`SmolStr` / `EcoString` / `CompactString`), enable the matching `buffa-descriptor` feature"
)]
pub trait ReflectElement: core::fmt::Debug {
#[must_use]
fn as_value_ref(&self) -> ValueRef<'_>;
}
pub trait ReflectMapKey: core::fmt::Debug + PartialEq {
#[must_use]
fn as_map_key_ref(&self) -> MapKeyRef<'_>;
}
macro_rules! impl_scalar_element {
($($t:ty => $variant:ident),* $(,)?) => {$(
impl ReflectElement for $t {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::$variant(*self)
}
}
)*};
}
impl_scalar_element! {
i32 => I32,
i64 => I64,
u32 => U32,
u64 => U64,
bool => Bool,
f32 => F32,
f64 => F64,
}
impl ReflectElement for &str {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::String(self)
}
}
impl ReflectElement for &[u8] {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::Bytes(self)
}
}
impl<E: Enumeration> ReflectElement for EnumValue<E> {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::EnumNumber(self.to_i32())
}
}
impl ReflectElement for String {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::String(self)
}
}
impl ReflectElement for Vec<u8> {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::Bytes(self)
}
}
impl ReflectElement for Bytes {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::Bytes(self)
}
}
impl ReflectElement for Value {
fn as_value_ref(&self) -> ValueRef<'_> {
self.as_ref()
}
}
#[cfg(feature = "smol_str")]
impl ReflectElement for buffa::smol_str::SmolStr {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::String(self.as_ref())
}
}
#[cfg(feature = "ecow")]
impl ReflectElement for buffa::ecow::EcoString {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::String(self.as_ref())
}
}
#[cfg(feature = "compact_str")]
impl ReflectElement for buffa::compact_str::CompactString {
fn as_value_ref(&self) -> ValueRef<'_> {
ValueRef::String(self.as_ref())
}
}
macro_rules! impl_scalar_key {
($($t:ty => $variant:ident),* $(,)?) => {$(
impl ReflectMapKey for $t {
fn as_map_key_ref(&self) -> MapKeyRef<'_> {
MapKeyRef::$variant(*self)
}
}
)*};
}
impl_scalar_key! {
i32 => I32,
i64 => I64,
u32 => U32,
u64 => U64,
bool => Bool,
}
impl ReflectMapKey for &str {
fn as_map_key_ref(&self) -> MapKeyRef<'_> {
MapKeyRef::String(self)
}
}
impl ReflectMapKey for String {
fn as_map_key_ref(&self) -> MapKeyRef<'_> {
MapKeyRef::String(self)
}
}
impl ReflectMapKey for &[u8] {
fn as_map_key_ref(&self) -> MapKeyRef<'_> {
MapKeyRef::String(core::str::from_utf8(self).unwrap_or(""))
}
}
impl<T: ReflectElement> ReflectList for RepeatedView<'_, T> {
fn len(&self) -> usize {
let elements: &[T] = self;
elements.len()
}
fn get(&self, idx: usize) -> Option<ValueRef<'_>> {
let elements: &[T] = self;
elements.get(idx).map(ReflectElement::as_value_ref)
}
fn for_each(&self, f: &mut dyn FnMut(ValueRef<'_>)) {
for elem in self.iter() {
f(elem.as_value_ref());
}
}
}
impl<K: ReflectMapKey, V: ReflectElement> ReflectMap for MapView<'_, K, V> {
fn len(&self) -> usize {
self.len_unique()
}
fn get(&self, key: &MapKey) -> Option<ValueRef<'_>> {
let want = key.as_ref();
self.iter()
.rev()
.find(|(k, _)| k.as_map_key_ref() == want)
.map(|(_, v)| v.as_value_ref())
}
fn get_str(&self, key: &str) -> Option<ValueRef<'_>> {
self.iter()
.rev()
.find(|(k, _)| matches!(k.as_map_key_ref(), MapKeyRef::String(s) if s == key))
.map(|(_, v)| v.as_value_ref())
}
fn for_each(&self, f: &mut dyn FnMut(MapKeyRef<'_>, ValueRef<'_>)) {
for (k, v) in self.iter_unique() {
f(k.as_map_key_ref(), v.as_value_ref());
}
}
}
impl<T: ReflectElement> ReflectList for Vec<T> {
fn len(&self) -> usize {
self.as_slice().len()
}
fn get(&self, idx: usize) -> Option<ValueRef<'_>> {
self.as_slice().get(idx).map(ReflectElement::as_value_ref)
}
fn for_each(&self, f: &mut dyn FnMut(ValueRef<'_>)) {
for elem in self {
f(elem.as_value_ref());
}
}
}
#[cfg(feature = "std")]
impl<K: ReflectMapKey, V: ReflectElement> ReflectMap for std::collections::HashMap<K, V> {
fn len(&self) -> usize {
Self::len(self)
}
fn get(&self, key: &MapKey) -> Option<ValueRef<'_>> {
let want = key.as_ref();
self.iter()
.find(|(k, _)| k.as_map_key_ref() == want)
.map(|(_, v)| v.as_value_ref())
}
fn get_str(&self, key: &str) -> Option<ValueRef<'_>> {
self.iter()
.find(|(k, _)| matches!(k.as_map_key_ref(), MapKeyRef::String(s) if s == key))
.map(|(_, v)| v.as_value_ref())
}
fn for_each(&self, f: &mut dyn FnMut(MapKeyRef<'_>, ValueRef<'_>)) {
for (k, v) in self {
f(k.as_map_key_ref(), v.as_value_ref());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
#[test]
fn repeated_scalar_list() {
let view: RepeatedView<'_, i32> = RepeatedView::new(vec![7, 11, 13]);
let list: &dyn ReflectList = &view;
assert_eq!(list.len(), 3);
assert!(!list.is_empty());
assert!(matches!(list.get(1), Some(ValueRef::I32(11))));
assert!(list.get(3).is_none());
let mut sum = 0;
list.for_each(&mut |v| {
if let ValueRef::I32(n) = v {
sum += n;
}
});
assert_eq!(sum, 31);
}
#[test]
fn repeated_string_list_is_borrowed() {
let view: RepeatedView<'_, &str> = RepeatedView::new(vec!["a", "b"]);
let list: &dyn ReflectList = &view;
assert_eq!(list.len(), 2);
assert!(matches!(list.get(0), Some(ValueRef::String("a"))));
assert!(matches!(list.get(1), Some(ValueRef::String("b"))));
}
#[test]
fn repeated_bytes_list() {
let a: &[u8] = &[0xDE, 0xAD];
let b: &[u8] = &[0xBE, 0xEF];
let view: RepeatedView<'_, &[u8]> = RepeatedView::new(vec![a, b]);
let list: &dyn ReflectList = &view;
match list.get(0) {
Some(ValueRef::Bytes(bytes)) => assert_eq!(bytes, &[0xDE, 0xAD]),
other => panic!("expected Bytes, got {other:?}"),
}
}
#[test]
fn empty_list() {
let view: RepeatedView<'_, i32> = RepeatedView::default();
let list: &dyn ReflectList = &view;
assert_eq!(list.len(), 0);
assert!(list.is_empty());
assert!(list.get(0).is_none());
}
#[test]
fn map_string_keyed() {
let view: MapView<'_, &str, i32> = MapView::new(vec![("apples", 3), ("oranges", 7)]);
let map: &dyn ReflectMap = &view;
assert_eq!(map.len(), 2);
assert!(!map.is_empty());
assert!(matches!(map.get_str("apples"), Some(ValueRef::I32(3))));
assert!(matches!(map.get_str("oranges"), Some(ValueRef::I32(7))));
assert!(map.get_str("durian").is_none());
assert!(matches!(
map.get(&MapKey::String("apples".into())),
Some(ValueRef::I32(3))
));
assert!(map.get(&MapKey::String("missing".into())).is_none());
let mut total = 0;
map.for_each(&mut |_k, v| {
if let ValueRef::I32(n) = v {
total += n;
}
});
assert_eq!(total, 10);
}
#[test]
fn map_int_keyed_get_str_returns_none() {
let view: MapView<'_, i32, &str> = MapView::new(vec![(1, "one"), (2, "two")]);
let map: &dyn ReflectMap = &view;
assert!(map.get_str("1").is_none());
assert!(matches!(
map.get(&MapKey::I32(2)),
Some(ValueRef::String("two"))
));
}
#[test]
fn map_last_write_wins_on_duplicate_keys() {
let view: MapView<'_, &str, i32> = MapView::new(vec![("k", 1), ("k", 2)]);
let map: &dyn ReflectMap = &view;
assert!(matches!(map.get_str("k"), Some(ValueRef::I32(2))));
assert!(matches!(
map.get(&MapKey::String("k".into())),
Some(ValueRef::I32(2))
));
assert_eq!(map.len(), 1);
let mut visits = Vec::new();
map.for_each(&mut |_k, v| {
if let ValueRef::I32(n) = v {
visits.push(n);
}
});
assert_eq!(visits, vec![2]);
}
#[test]
fn map_bytes_keyed_utf8() {
let apples: &[u8] = b"apples";
let view: MapView<'_, &[u8], i32> = MapView::new(vec![(apples, 5)]);
let map: &dyn ReflectMap = &view;
assert_eq!(map.len(), 1);
assert!(matches!(map.get_str("apples"), Some(ValueRef::I32(5))));
let mut keys = Vec::new();
map.for_each(&mut |k, _v| {
if let MapKeyRef::String(s) = k {
keys.push(s.to_string());
}
});
assert_eq!(keys, vec!["apples".to_string()]);
}
#[test]
fn owned_vec_of_string() {
let v: Vec<String> = vec!["a".to_string(), "b".to_string()];
let list: &dyn ReflectList = &v;
assert_eq!(list.len(), 2);
assert!(matches!(list.get(0), Some(ValueRef::String("a"))));
assert!(matches!(list.get(1), Some(ValueRef::String("b"))));
}
#[test]
fn owned_vec_of_value_still_reflects() {
let v: Vec<Value> = vec![Value::I32(7), Value::I32(11)];
let list: &dyn ReflectList = &v;
assert_eq!(list.len(), 2);
assert!(matches!(list.get(1), Some(ValueRef::I32(11))));
}
#[cfg(feature = "std")]
#[test]
fn owned_hashmap() {
let mut m: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
m.insert("apples".to_string(), 3);
m.insert("oranges".to_string(), 7);
let map: &dyn ReflectMap = &m;
assert_eq!(map.len(), 2);
assert!(matches!(map.get_str("apples"), Some(ValueRef::I32(3))));
assert!(matches!(
map.get(&MapKey::String("oranges".into())),
Some(ValueRef::I32(7))
));
assert!(map.get_str("durian").is_none());
let mut total = 0;
map.for_each(&mut |_k, v| {
if let ValueRef::I32(n) = v {
total += n;
}
});
assert_eq!(total, 10);
}
}