cosmwasm: Add cw_transcode crate
The cw_transcode crate provides a way to transcode any arbitrary rust struct into a `cosmwasm_std::Event` via that struct's `Serialize` impl, ensuring that the event attribute values are encoded as proper json. This will make it easier for client code to parse the event back into structured data without having to write custom parsing code for each individual event type.
This commit is contained in:
parent
ce1f3adc23
commit
3c914c725a
|
@ -594,6 +594,18 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cw_transcode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde-json-wasm",
|
||||
"serde_bytes",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.2"
|
||||
|
@ -967,6 +979,9 @@ name = "hex"
|
|||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
|
|
|
@ -9,6 +9,7 @@ members = [
|
|||
"packages/accounting",
|
||||
"contracts/wormchain-accounting",
|
||||
"packages/wormhole-bindings",
|
||||
"packages/cw_transcode",
|
||||
]
|
||||
|
||||
# Needed to prevent unwanted feature unification between normal builds and dev builds. See
|
||||
|
@ -28,6 +29,7 @@ overflow-checks = true
|
|||
|
||||
[patch.crates-io]
|
||||
accounting = { path = "packages/accounting" }
|
||||
cw_transcode = { path = "packages/cw_transcode" }
|
||||
cw20-wrapped-2 = { path = "contracts/cw20-wrapped" }
|
||||
serde_wormhole = { path = "../sdk/rust/serde_wormhole" }
|
||||
token-bridge-terra-2 = { path = "contracts/token-bridge" }
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "cw_transcode"
|
||||
version = "0.1.0"
|
||||
authors = ["Wormhole Project Contributors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cosmwasm-std = "1"
|
||||
serde = { version = "1", default-features = false }
|
||||
serde-json-wasm = "0.4"
|
||||
thiserror = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
hex = { version = "0.4", features = ["serde"] }
|
||||
serde_bytes = "0.11"
|
|
@ -0,0 +1,26 @@
|
|||
use std::fmt;
|
||||
|
||||
use serde::ser;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
Custom(Box<str>),
|
||||
#[error("cannot transcode non-struct type to `Event`")]
|
||||
NotAStruct,
|
||||
#[error("{0}")]
|
||||
Json(#[from] serde_json_wasm::ser::Error),
|
||||
#[error("cannot transcode more than one struct to `Event`")]
|
||||
MultipleStructs,
|
||||
#[error("no event produced by serialization")]
|
||||
NoEvent,
|
||||
}
|
||||
|
||||
impl ser::Error for Error {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: fmt::Display,
|
||||
{
|
||||
Error::Custom(msg.to_string().into_boxed_str())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
//! This crate provides a mechanism to convert arbitrary rust structs into `cosmwasm_std::Event`s
|
||||
//! via that struct's `Serialize` impl.
|
||||
|
||||
use cosmwasm_std::Event;
|
||||
use serde::Serialize;
|
||||
|
||||
mod error;
|
||||
mod ser;
|
||||
|
||||
pub use error::Error;
|
||||
use ser::Serializer;
|
||||
|
||||
/// Convert `value` into a `cosmwasm_std::Event` via its `Serialize` impl.
|
||||
///
|
||||
/// `value` must serialize as exactly one regular struct, a unit struct, a struct variant of an
|
||||
/// enum, or an `Option` that contains a value that serializes as one of of the previous 3 types.
|
||||
/// Attempting to convert any other type (including `Option::None`) to an `Event` will return
|
||||
/// `Error::NotAStruct`.
|
||||
///
|
||||
/// The name of the struct will become the type of the returned event while the fields of the struct
|
||||
/// will become the event attributes. In the case of a struct variant of an enum, the type of the
|
||||
/// event will be "{name}::{variant}". Field values are encoded using the `serde-json-wasm` crate
|
||||
/// and field types may be any type supported by that crate.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # fn example() -> Result<(), cw_transcode::Error> {
|
||||
/// # use cosmwasm_std::{Binary, Event};
|
||||
/// # use serde::Serialize;
|
||||
/// #
|
||||
/// # #[derive(Serialize)]
|
||||
/// # struct Nested {
|
||||
/// # f1: u32,
|
||||
/// # f2: String,
|
||||
/// # }
|
||||
/// #
|
||||
/// # #[derive(Serialize)]
|
||||
/// # struct Example {
|
||||
/// # primitive: i64,
|
||||
/// # nested: Nested,
|
||||
/// # binary: Binary,
|
||||
/// # }
|
||||
/// #
|
||||
/// use cw_transcode::to_event;
|
||||
///
|
||||
/// let e = Example {
|
||||
/// // Primitive values are supported.
|
||||
/// primitive: 0x9a82f2b2865c2fdau64 as i64,
|
||||
///
|
||||
/// // Nested struct fields are encoded as json objects.
|
||||
/// nested: Nested {
|
||||
/// f1: 0xdbc7b8a1u32,
|
||||
/// f2: "TEST".to_string(),
|
||||
/// },
|
||||
///
|
||||
/// // Other types supported by `serde-json-wasm` are also fine.
|
||||
/// binary: Binary(vec![
|
||||
/// 0xdb, 0x78, 0x97, 0x0e, 0xf2, 0x55, 0x97, 0xf4, 0x66, 0x11, 0x91, 0x0f, 0x50, 0x57,
|
||||
/// 0xb8, 0xe7,
|
||||
/// ]),
|
||||
/// };
|
||||
///
|
||||
/// let evt = to_event(&e)?;
|
||||
///
|
||||
/// let expected = Event::new("Example")
|
||||
/// .add_attribute("primitive", "-7313015996323975206")
|
||||
/// .add_attribute("nested", r#"{"f1":3687299233,"f2":"TEST"}"#)
|
||||
/// .add_attribute("binary", "\"23iXDvJVl/RmEZEPUFe45w==\"");
|
||||
///
|
||||
/// assert_eq!(expected, evt);
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # example().unwrap();
|
||||
/// ```
|
||||
pub fn to_event<T: Serialize + ?Sized>(value: &T) -> Result<Event, Error> {
|
||||
let mut s = Serializer::new();
|
||||
value.serialize(&mut s)?;
|
||||
s.finish().ok_or(Error::NoEvent)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use std::{any::type_name, collections::BTreeMap};
|
||||
|
||||
use cosmwasm_std::Binary;
|
||||
use serde_bytes::ByteBuf;
|
||||
|
||||
#[test]
|
||||
fn unsupported() {
|
||||
macro_rules! test_unsupported {
|
||||
($($ty:ty),* $(,)?) => {
|
||||
$(
|
||||
let x: $ty = Default::default();
|
||||
let name = type_name::<$ty>();
|
||||
let err = to_event(&x).expect_err(name);
|
||||
assert!(matches!(err, Error::NotAStruct), "{name}");
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
test_unsupported!(
|
||||
i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, f32, f64, char,
|
||||
String, Vec<u8>, ByteBuf, BTreeMap<u32, u32>, Option<u64>, (), (u32, f32, i64)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
#[derive(Serialize)]
|
||||
struct Transfer {
|
||||
tx_hash: Binary,
|
||||
timestamp: u32,
|
||||
nonce: u32,
|
||||
emitter_chain: u16,
|
||||
#[serde(with = "hex")]
|
||||
emitter_address: [u8; 32],
|
||||
sequence: u64,
|
||||
consistency_level: u8,
|
||||
payload: Binary,
|
||||
}
|
||||
|
||||
let tx = Transfer {
|
||||
tx_hash: Binary(vec![
|
||||
0x82, 0xea, 0x25, 0x36, 0xc5, 0xd1, 0x67, 0x18, 0x30, 0xcb, 0x49, 0x12, 0x0f, 0x94,
|
||||
0x47, 0x9e, 0x34, 0xb5, 0x45, 0x96, 0xa8, 0xdd, 0x36, 0x9f, 0xbc, 0x26, 0x66, 0x66,
|
||||
0x7a, 0x76, 0x5f, 0x4b,
|
||||
]),
|
||||
timestamp: 1672860466,
|
||||
nonce: 0,
|
||||
emitter_chain: 2,
|
||||
emitter_address: [
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x90,
|
||||
0xfb, 0x16, 0x72, 0x08, 0xaf, 0x45, 0x5b, 0xb1, 0x37, 0x78, 0x01, 0x63, 0xb7, 0xb7,
|
||||
0xa9, 0xa1, 0x0c, 0x16,
|
||||
],
|
||||
sequence: 1672860466,
|
||||
consistency_level: 15,
|
||||
payload: Binary(vec![
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xe0, 0xb6,
|
||||
0xb3, 0xa7, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x2d, 0x8b, 0xe6, 0xbf, 0x0b, 0xaa, 0x74, 0xe0, 0xa9, 0x07, 0x01,
|
||||
0x66, 0x79, 0xca, 0xe9, 0x19, 0x0e, 0x80, 0xdd, 0x0a, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x08, 0x20, 0x98, 0x3f,
|
||||
0x33, 0x45, 0x6c, 0xe7, 0xbe, 0xb3, 0xa0, 0x46, 0xf5, 0xa8, 0x3f, 0xa3, 0x4f, 0x02,
|
||||
0x7d, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
]),
|
||||
};
|
||||
|
||||
let expected = Event::new("Transfer")
|
||||
.add_attribute(
|
||||
"tx_hash",
|
||||
"\"guolNsXRZxgwy0kSD5RHnjS1RZao3TafvCZmZnp2X0s=\"",
|
||||
)
|
||||
.add_attribute("timestamp", "1672860466")
|
||||
.add_attribute("nonce", "0")
|
||||
.add_attribute("emitter_chain", "2")
|
||||
.add_attribute(
|
||||
"emitter_address",
|
||||
"\"0000000000000000000000000290fb167208af455bb137780163b7b7a9a10c16\"",
|
||||
)
|
||||
.add_attribute("sequence", "1672860466")
|
||||
.add_attribute("consistency_level", "15")
|
||||
.add_attribute("payload", "\"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3gtrOnZAAAAAAAAAAAAAAAAAAALYvmvwuqdOCpBwFmecrpGQ6A3QoAAgAAAAAAAAAAAAAAAMEIIJg/M0Vs576zoEb1qD+jTwJ9DCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\"");
|
||||
|
||||
let actual = to_event(&tx).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
#[derive(Serialize)]
|
||||
struct Data {
|
||||
a: u32,
|
||||
b: String,
|
||||
}
|
||||
|
||||
let d = Some(Data {
|
||||
a: 17,
|
||||
b: "BEEF".into(),
|
||||
});
|
||||
|
||||
let expected = Event::new("Data")
|
||||
.add_attribute("a", "17")
|
||||
.add_attribute("b", "\"BEEF\"");
|
||||
|
||||
let actual = to_event(&d).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_struct() {
|
||||
#[derive(Serialize)]
|
||||
struct MyEvent;
|
||||
|
||||
let expected = Event::new("MyEvent");
|
||||
let actual = to_event(&MyEvent).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_variants() {
|
||||
#[derive(Serialize)]
|
||||
enum MyEvent {
|
||||
A,
|
||||
B(u32),
|
||||
C { f1: u64, f2: String },
|
||||
D(u16, u16, u32),
|
||||
}
|
||||
|
||||
// Unit variants.
|
||||
{
|
||||
let expected = Event::new("MyEvent::A");
|
||||
let actual = to_event(&MyEvent::A).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
// Newtype variants.
|
||||
{
|
||||
let err = to_event(&MyEvent::B(19)).unwrap_err();
|
||||
assert!(matches!(err, Error::NotAStruct));
|
||||
}
|
||||
|
||||
// Struct variants.
|
||||
{
|
||||
let c = MyEvent::C {
|
||||
f1: 500,
|
||||
f2: "test struct variant".into(),
|
||||
};
|
||||
let expected = Event::new("MyEvent::C")
|
||||
.add_attribute("f1", "500")
|
||||
.add_attribute("f2", "\"test struct variant\"");
|
||||
let actual = to_event(&c).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
// Tuple variants.
|
||||
{
|
||||
let err = to_event(&MyEvent::D(37, 1926, 189174)).unwrap_err();
|
||||
assert!(matches!(err, Error::NotAStruct));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
#[derive(Serialize)]
|
||||
struct Nested {
|
||||
a: u32,
|
||||
b: Binary,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Outer {
|
||||
nested: Nested,
|
||||
c: String,
|
||||
}
|
||||
|
||||
let o = Outer {
|
||||
nested: Nested {
|
||||
a: 0xfeb42045,
|
||||
b: Binary(vec![
|
||||
0x11, 0x7d, 0x83, 0xa4, 0x06, 0xbf, 0x3e, 0x50, 0xe1, 0xaa, 0x19, 0x89, 0xc3,
|
||||
0x00, 0xea, 0xaf,
|
||||
]),
|
||||
},
|
||||
c: "TEST".into(),
|
||||
};
|
||||
|
||||
let expected = Event::new("Outer")
|
||||
.add_attribute(
|
||||
"nested",
|
||||
r#"{"a":4273217605,"b":"EX2DpAa/PlDhqhmJwwDqrw=="}"#,
|
||||
)
|
||||
.add_attribute("c", "\"TEST\"");
|
||||
let actual = to_event(&o).unwrap();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,328 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use cosmwasm_std::{Attribute, Event};
|
||||
use serde::{
|
||||
ser::{Impossible, SerializeStruct, SerializeStructVariant},
|
||||
Serialize,
|
||||
};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub struct Serializer(Option<Event>);
|
||||
|
||||
impl Serializer {
|
||||
pub const fn new() -> Self {
|
||||
Self(None)
|
||||
}
|
||||
|
||||
pub fn finish(self) -> Option<Event> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> serde::Serializer for &'a mut Serializer {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
type SerializeSeq = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTuple = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeMap = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeStruct = Transcoder<'a>;
|
||||
type SerializeStructVariant = Transcoder<'a>;
|
||||
|
||||
#[inline]
|
||||
fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_i128(self, _: i128) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_u128(self, _: u128) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
value.serialize(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
|
||||
if self.0.is_none() {
|
||||
self.0 = Some(Event::new(name));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::MultipleStructs)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
if self.0.is_none() {
|
||||
self.0 = Some(Event::new(format!("{name}::{variant}")));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::MultipleStructs)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_struct<T: ?Sized>(
|
||||
self,
|
||||
_: &'static str,
|
||||
_: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_newtype_variant<T: ?Sized>(
|
||||
self,
|
||||
_: &'static str,
|
||||
_variant_index: u32,
|
||||
_: &'static str,
|
||||
_: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_: &'static str,
|
||||
_variant_index: u32,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Self::Error> {
|
||||
if self.0.is_none() {
|
||||
Ok(Transcoder {
|
||||
serializer: self,
|
||||
event: Event::new(format!("{name}::{variant}")),
|
||||
})
|
||||
} else {
|
||||
Err(Error::MultipleStructs)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
name: &'static str,
|
||||
_: usize,
|
||||
) -> Result<Self::SerializeStruct, Self::Error> {
|
||||
if self.0.is_none() {
|
||||
Ok(Transcoder {
|
||||
serializer: self,
|
||||
event: Event::new(name),
|
||||
})
|
||||
} else {
|
||||
Err(Error::MultipleStructs)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_str<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
Err(Error::NotAStruct)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_human_readable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Transcoder<'a> {
|
||||
serializer: &'a mut Serializer,
|
||||
event: Event,
|
||||
}
|
||||
|
||||
impl<'a> Transcoder<'a> {
|
||||
fn serialize_field<T: ?Sized>(&mut self, k: &'static str, v: &T) -> Result<(), Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let key = k.into();
|
||||
let value = serde_json_wasm::to_string(v)?;
|
||||
self.event.attributes.push(Attribute { key, value });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<(), Error> {
|
||||
self.serializer.0 = Some(self.event);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeStruct for Transcoder<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
k: &'static str,
|
||||
v: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.serialize_field(k, v)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SerializeStructVariant for Transcoder<'a> {
|
||||
type Ok = ();
|
||||
type Error = Error;
|
||||
|
||||
#[inline]
|
||||
fn serialize_field<T: ?Sized>(
|
||||
&mut self,
|
||||
k: &'static str,
|
||||
v: &T,
|
||||
) -> Result<Self::Ok, Self::Error>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
self.serialize_field(k, v)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn end(self) -> Result<Self::Ok, Self::Error> {
|
||||
self.end()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue