Skip to content

Commit 0788f30

Browse files
committed
Implement a version of Schema types that are owned, using the heap, and can be
punned or converted with existing typed or serialized schema types
1 parent f878536 commit 0788f30

File tree

3 files changed

+250
-7
lines changed

3 files changed

+250
-7
lines changed

source/postcard/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ pub mod experimental {
8181
pub use crate::schema::{NamedType, NamedValue, NamedVariant, Schema, SdmTy, Varint};
8282
// NOTE: ...and this is the derive macro
8383
pub use postcard_derive::Schema;
84+
85+
#[cfg(any(feature = "use-std", feature = "alloc"))]
86+
pub use crate::schema::owned::{
87+
OwnedNamedType, OwnedNamedValue, OwnedNamedVariant, OwnedSdmTy,
88+
};
8489
}
8590
}
8691

source/postcard/src/schema.rs

Lines changed: 192 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use serde::Serialize;
1+
use serde::{Deserialize, Serialize};
22

33
/// A schema type representing a variably encoded integer
4-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
4+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
55
pub enum Varint {
66
/// A variably encoded i16
77
I16,
@@ -26,7 +26,7 @@ pub enum Varint {
2626
}
2727

2828
/// Serde Data Model Types (and friends)
29-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
29+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
3030
pub enum SdmTy {
3131
/// The `bool` Serde Data Model Type
3232
Bool,
@@ -104,7 +104,7 @@ pub enum SdmTy {
104104
}
105105

106106
/// A data type with a name - e.g. a field of a Struct
107-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
107+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
108108
pub struct NamedValue {
109109
/// The name of this value
110110
pub name: &'static str,
@@ -113,7 +113,7 @@ pub struct NamedValue {
113113
}
114114

115115
/// A data type - e.g. a custom `struct Foo{ ... }` type
116-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
116+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
117117
pub struct NamedType {
118118
/// The name of this type
119119
pub name: &'static str,
@@ -122,7 +122,7 @@ pub struct NamedType {
122122
}
123123

124124
/// An enum variant with a name, e.g. `T::Bar(...)`
125-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
125+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
126126
pub struct NamedVariant {
127127
/// The name of this variant
128128
pub name: &'static str,
@@ -278,3 +278,189 @@ impl Schema for alloc::string::String {
278278
ty: &SdmTy::String,
279279
};
280280
}
281+
282+
#[cfg(any(feature = "use-std", feature = "alloc"))]
283+
pub(crate) mod owned {
284+
use super::*;
285+
286+
#[cfg(feature = "use-std")]
287+
use std::{boxed::Box, string::String, vec::Vec};
288+
289+
#[cfg(all(not(feature = "use-std"), feature = "alloc"))]
290+
use alloc::{
291+
boxed::Box,
292+
string::{String, ToString},
293+
vec::Vec,
294+
};
295+
296+
/// Serde Data Model Types (and friends)
297+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
298+
pub enum OwnedSdmTy {
299+
/// The `bool` Serde Data Model Type
300+
Bool,
301+
302+
/// The `i8` Serde Data Model Type
303+
I8,
304+
305+
/// The `u8` Serde Data Model Type
306+
U8,
307+
308+
/// The Serde Data Model Type for variably length encoded integers
309+
Varint(Varint),
310+
311+
/// The `f32` Serde Data Model Type
312+
F32,
313+
314+
/// The `f64 Serde Data Model Type
315+
F64,
316+
317+
/// The `char` Serde Data Model Type
318+
Char,
319+
320+
/// The `String` Serde Data Model Type
321+
String,
322+
323+
/// The `[u8; N]` Serde Data Model Type
324+
ByteArray,
325+
326+
/// The `Option<T>` Serde Data Model Type
327+
Option(Box<OwnedNamedType>),
328+
329+
/// The `()` Serde Data Model Type
330+
Unit,
331+
332+
/// The "unit struct" Serde Data Model Type
333+
UnitStruct,
334+
335+
/// The "unit variant" Serde Data Model Type
336+
UnitVariant,
337+
338+
/// The "newtype struct" Serde Data Model Type
339+
NewtypeStruct(Box<OwnedNamedType>),
340+
341+
/// The "newtype variant" Serde Data Model Type
342+
NewtypeVariant(Box<OwnedNamedType>),
343+
344+
/// The "Sequence" Serde Data Model Type
345+
Seq(Box<OwnedNamedType>),
346+
347+
/// The "Tuple" Serde Data Model Type
348+
Tuple(Vec<OwnedNamedType>),
349+
350+
/// The "Tuple Struct" Serde Data Model Type
351+
TupleStruct(Vec<OwnedNamedType>),
352+
353+
/// The "Tuple Variant" Serde Data Model Type
354+
TupleVariant(Vec<OwnedNamedType>),
355+
356+
/// The "Map" Serde Data Model Type
357+
Map {
358+
/// The map "Key" type
359+
key: Box<OwnedNamedType>,
360+
/// The map "Value" type
361+
val: Box<OwnedNamedType>,
362+
},
363+
364+
/// The "Struct" Serde Data Model Type
365+
Struct(Vec<OwnedNamedValue>),
366+
367+
/// The "Struct Variant" Serde Data Model Type
368+
StructVariant(Vec<OwnedNamedValue>),
369+
370+
/// The "Enum" Serde Data Model Type (which contains any of the "Variant" types)
371+
Enum(Vec<OwnedNamedVariant>),
372+
}
373+
374+
impl From<&SdmTy> for OwnedSdmTy {
375+
fn from(other: &SdmTy) -> Self {
376+
match other {
377+
SdmTy::Bool => Self::Bool,
378+
SdmTy::I8 => Self::I8,
379+
SdmTy::U8 => Self::U8,
380+
SdmTy::Varint(v) => Self::Varint(*v),
381+
SdmTy::F32 => Self::F32,
382+
SdmTy::F64 => Self::F64,
383+
SdmTy::Char => Self::Char,
384+
SdmTy::String => Self::String,
385+
SdmTy::ByteArray => Self::ByteArray,
386+
SdmTy::Option(o) => Self::Option(Box::new((*o).into())),
387+
SdmTy::Unit => Self::Unit,
388+
SdmTy::UnitStruct => Self::UnitStruct,
389+
SdmTy::UnitVariant => Self::UnitVariant,
390+
SdmTy::NewtypeStruct(nts) => Self::NewtypeStruct(Box::new((*nts).into())),
391+
SdmTy::NewtypeVariant(ntv) => Self::NewtypeVariant(Box::new((*ntv).into())),
392+
SdmTy::Seq(s) => Self::Seq(Box::new((*s).into())),
393+
SdmTy::Tuple(t) => Self::Tuple(t.iter().map(|i| (*i).into()).collect()),
394+
SdmTy::TupleStruct(ts) => {
395+
Self::TupleStruct(ts.iter().map(|i| (*i).into()).collect())
396+
}
397+
SdmTy::TupleVariant(tv) => {
398+
Self::TupleVariant(tv.iter().map(|i| (*i).into()).collect())
399+
}
400+
SdmTy::Map { key, val } => Self::Map {
401+
key: Box::new((*key).into()),
402+
val: Box::new((*val).into()),
403+
},
404+
SdmTy::Struct(s) => Self::Struct(s.iter().map(|i| (*i).into()).collect()),
405+
SdmTy::StructVariant(sv) => {
406+
Self::StructVariant(sv.iter().map(|i| (*i).into()).collect())
407+
}
408+
SdmTy::Enum(e) => Self::Enum(e.iter().map(|i| (*i).into()).collect()),
409+
}
410+
}
411+
}
412+
413+
/// A data type with a name - e.g. a field of a Struct
414+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
415+
pub struct OwnedNamedValue {
416+
/// The name of this value
417+
pub name: String,
418+
/// The type of this value
419+
pub ty: OwnedNamedType,
420+
}
421+
422+
impl From<&NamedValue> for OwnedNamedValue {
423+
fn from(value: &NamedValue) -> Self {
424+
Self {
425+
name: value.name.to_string(),
426+
ty: value.ty.into(),
427+
}
428+
}
429+
}
430+
431+
/// A data type - e.g. a custom `struct Foo{ ... }` type
432+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
433+
pub struct OwnedNamedType {
434+
/// The name of this type
435+
pub name: String,
436+
/// The type
437+
pub ty: OwnedSdmTy,
438+
}
439+
440+
impl From<&NamedType> for OwnedNamedType {
441+
fn from(value: &NamedType) -> Self {
442+
Self {
443+
name: value.name.to_string(),
444+
ty: value.ty.into(),
445+
}
446+
}
447+
}
448+
449+
/// An enum variant with a name, e.g. `T::Bar(...)`
450+
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
451+
pub struct OwnedNamedVariant {
452+
/// The name of this variant
453+
pub name: String,
454+
/// The type of this variant
455+
pub ty: OwnedSdmTy,
456+
}
457+
458+
impl From<&NamedVariant> for OwnedNamedVariant {
459+
fn from(value: &NamedVariant) -> Self {
460+
Self {
461+
name: value.name.to_string(),
462+
ty: value.ty.into(),
463+
}
464+
}
465+
}
466+
}

source/postcard/tests/schema.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#![cfg(feature = "experimental-derive")]
22

3-
use postcard::experimental::schema::{NamedType, NamedValue, NamedVariant, Schema, SdmTy, Varint};
3+
use postcard::experimental::schema::{
4+
NamedType, NamedValue, NamedVariant, OwnedNamedType, Schema, SdmTy, Varint,
5+
};
46

57
const U8_SCHEMA: NamedType = NamedType {
68
name: "u8",
@@ -161,3 +163,53 @@ fn test_slice_serialize() {
161163
Slice::SCHEMA
162164
);
163165
}
166+
167+
#[allow(unused)]
168+
#[derive(Debug, Schema)]
169+
enum TestEnum<'a> {
170+
Alpha,
171+
Beta(u32),
172+
Gamma { a: bool, b: &'a [u8] },
173+
Delta(f32, Option<&'a str>),
174+
Epsilon(TestStruct1),
175+
}
176+
177+
#[allow(unused)]
178+
#[derive(Debug, Schema)]
179+
struct TestStruct1 {
180+
a: i8,
181+
b: i16,
182+
c: i32,
183+
d: i64,
184+
}
185+
186+
#[allow(unused)]
187+
#[derive(Debug, Schema)]
188+
struct TestStruct2<'a> {
189+
x: TestEnum<'a>,
190+
y: TestStruct1,
191+
z: Result<TestStruct1, u32>,
192+
}
193+
194+
#[test]
195+
fn owned_punning() {
196+
let borrowed_schema = TestStruct2::SCHEMA;
197+
let owned_schema: OwnedNamedType = borrowed_schema.into();
198+
199+
// Check that they are the same on the wire when serialized
200+
let ser_borrowed_schema = postcard::to_stdvec(borrowed_schema).unwrap();
201+
let ser_owned_schema = postcard::to_stdvec(&owned_schema).unwrap();
202+
assert_eq!(ser_borrowed_schema, ser_owned_schema);
203+
204+
// TODO: This is wildly repetitive, and likely could benefit from interning of
205+
// repeated types, strings, etc.
206+
assert_eq!(ser_borrowed_schema.len(), 282);
207+
208+
// Check that we round-trip correctly
209+
let deser_borrowed_schema =
210+
postcard::from_bytes::<OwnedNamedType>(&ser_borrowed_schema).unwrap();
211+
let deser_owned_schema = postcard::from_bytes::<OwnedNamedType>(&ser_owned_schema).unwrap();
212+
assert_eq!(deser_borrowed_schema, deser_owned_schema);
213+
assert_eq!(deser_borrowed_schema, owned_schema);
214+
assert_eq!(deser_owned_schema, owned_schema);
215+
}

0 commit comments

Comments
 (0)