Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit fc81756

Browse files
More tests around FieldSlot (#101)
1 parent b307ad6 commit fc81756

File tree

3 files changed

+90
-4
lines changed

3 files changed

+90
-4
lines changed

Justfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ check:
2828

2929
miri:
3030
cargo +nightly miri run --example opinions -F json
31+
cargo +nightly miri test -p merde_core

merde_core/src/deserialize.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
any::TypeId,
23
borrow::Cow,
34
collections::HashMap,
45
future::Future,
@@ -302,6 +303,44 @@ pub trait Deserializer<'s>: std::fmt::Debug {
302303
}
303304
}
304305

306+
mod mini_typeid {
307+
// vendored straight from https://github.com/dtolnay/typeid — which is dual-licensed under
308+
// MIT and Apache-2.0, just like merde.
309+
//
310+
// We don't really need const type_id construction or older rustc support, so this is a minimal
311+
// take on it.
312+
313+
use std::{any::TypeId, marker::PhantomData};
314+
315+
#[must_use]
316+
#[inline(always)]
317+
pub fn of<T>() -> TypeId
318+
where
319+
T: ?Sized,
320+
{
321+
trait NonStaticAny {
322+
fn get_type_id(&self) -> TypeId
323+
where
324+
Self: 'static;
325+
}
326+
327+
impl<T: ?Sized> NonStaticAny for PhantomData<T> {
328+
#[inline(always)]
329+
fn get_type_id(&self) -> TypeId
330+
where
331+
Self: 'static,
332+
{
333+
TypeId::of::<T>()
334+
}
335+
}
336+
337+
let phantom_data = PhantomData::<T>;
338+
NonStaticAny::get_type_id(unsafe {
339+
std::mem::transmute::<&dyn NonStaticAny, &(dyn NonStaticAny + 'static)>(&phantom_data)
340+
})
341+
}
342+
}
343+
305344
/// Allows filling in a field of a struct while deserializing.
306345
///
307346
/// Enforces some type safety at runtime, by carrying lifetimes
@@ -310,7 +349,8 @@ pub trait Deserializer<'s>: std::fmt::Debug {
310349
/// actually badly UB though. I should ask miri.
311350
pub struct FieldSlot<'s, 'borrow> {
312351
option: *mut Option<()>,
313-
type_name_of_option_field: &'static str,
352+
type_id_of_field: TypeId,
353+
type_name_of_field: &'static str,
314354
_phantom: PhantomData<(&'s (), &'borrow mut ())>,
315355
}
316356

@@ -323,15 +363,22 @@ impl<'s, 'borrow> FieldSlot<'s, 'borrow> {
323363
option: unsafe {
324364
std::mem::transmute::<*mut Option<T>, *mut Option<()>>(option as *mut _)
325365
},
326-
type_name_of_option_field: std::any::type_name::<Option<T>>(),
366+
type_id_of_field: mini_typeid::of::<T>(),
367+
type_name_of_field: std::any::type_name::<T>(),
327368
_phantom: PhantomData,
328369
}
329370
}
330371

331372
/// Fill this field with a value.
332373
pub fn fill<T: 's>(self, value: T) {
333-
let type_name_of_option_value = std::any::type_name::<Option<T>>();
334-
assert_eq!(self.type_name_of_option_field, type_name_of_option_value);
374+
let type_id_of_value = mini_typeid::of::<T>();
375+
assert_eq!(
376+
self.type_id_of_field,
377+
type_id_of_value,
378+
"tried to assign a \x1b[33m{}\x1b[0m to a slot of type \x1b[34m{}\x1b[0m",
379+
std::any::type_name::<T>(),
380+
self.type_name_of_field,
381+
);
335382

336383
unsafe {
337384
let option_ptr: *mut Option<T> = std::mem::transmute(self.option);
@@ -1023,3 +1070,6 @@ impl Future for ReturnPendingOnce {
10231070
}
10241071
}
10251072
}
1073+
1074+
#[cfg(test)]
1075+
mod tests;

merde_core/src/deserialize/tests.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use super::FieldSlot;
2+
3+
#[test]
4+
fn test_fieldslot_no_assign() {
5+
let mut option: Option<i32> = None;
6+
7+
{
8+
let slot = FieldSlot::new(&mut option);
9+
// let it drop
10+
let _ = slot;
11+
}
12+
13+
assert!(option.is_none());
14+
}
15+
16+
#[test]
17+
fn test_fieldslot_with_assign() {
18+
let mut option: Option<i32> = None;
19+
20+
{
21+
let slot = FieldSlot::new(&mut option);
22+
slot.fill::<i32>(42);
23+
}
24+
25+
assert_eq!(option, Some(42));
26+
}
27+
28+
#[test]
29+
#[should_panic(expected = "tried to assign")]
30+
fn test_fieldslot_with_assign_mismatched_type() {
31+
let mut option: Option<String> = None;
32+
33+
let slot = FieldSlot::new(&mut option);
34+
slot.fill::<i32>(42);
35+
}

0 commit comments

Comments
 (0)