3 unstable releases

0.2.0 Mar 15, 2024
0.1.1 Mar 7, 2024
0.1.0 Jan 2, 2024

#16 in #pact

Download history 1/week @ 2023-12-31 23/week @ 2024-02-18 19/week @ 2024-02-25 149/week @ 2024-03-03 164/week @ 2024-03-10 64/week @ 2024-03-17 1/week @ 2024-03-24 40/week @ 2024-03-31 2/week @ 2024-04-07

158 downloads per month
Used in pact-crypto

AGPL-3.0-only

105KB
2K SLoC

Macros for generating Rust types from TOML Pacts, and deriving Pact codecs for Rust types.

Generating Rust Types from TOML Pacts

The pact_toml macro generates Rust types from a string containing a Pact TOML:

# use pact_derive::pact_toml;
# use pact::codec::*;

// The string can be an anonymous constant like `_`;
// it will be fully replaced  by the generated code.
#[pact_toml]
const _: &str = r#"
pact = "MyGreeter"

[data.1. Request]
message = 'string'

[data.2. Response]
message = 'string'
"#;

# fn main() {
// A unique struct will be generated for
// each data type in the pact.
let request = Request { message: "Hello!".into() };

// An enum will be generated with variants for
// each data type in the pact. The enum's name
// will be the pact's name, with `Data` appended.
let data = MyGreeterData::from(request);
assert_eq!("Hello!", match data {
    MyGreeterData::Request(Request { message }) => message,
    _ => unimplemented!(),
});

// The structs and enum have auto-generated pact codecs.
# let request = Request { message: "Hello!".into() };
# let data = MyGreeterData::from(request.clone());
let mut request_bytes = vec![];
request_bytes.write_data(&request).unwrap();
let mut data_bytes = vec![];
data_bytes.write_data(&data).unwrap();
assert_eq!(request_bytes, data_bytes);

// The enum can be used to safely decode
// bytes containing arbitrary pact data.
let data = MyGreeterData::decode_from(&mut data_bytes.as_slice()).unwrap();
assert_eq!("Hello!", match data {
    MyGreeterData::Request(Request { message }) => message,
    _ => unimplemented!(),
});
# }

Deriving Pact Entry Codecs for Rust Types

The derive(PactCodec) macro derives a pact codec (encoder and decoder) for a Rust struct:

# use pact_derive::PactCodec;
# use pact::codec::*;

# #[derive(Debug, Default, PartialEq)]
#[derive(PactCodec)]
struct MyRequest {
    timestamp: u64,
    message: String,
}

# fn main() {
let request = MyRequest {
    message: "Hello!".into(),
    timestamp: 1337,
};

// The struct can encode to and decode
// from pact-encoded data.
let mut request_bytes = vec![];
request_bytes.write_data(&request).unwrap();
let decoded_request = MyRequest::decode_from(&mut request_bytes.as_slice()).unwrap();
assert_eq!(request, decoded_request);
# }

If a struct represents a data type in a Pact, an ordinal for the data type may be specified by adding #[pact(ordinal = 96)] to the struct, where 96 is an example ordinal.

If a field is not Pact-encodable, or should not be included during encoding or decoding, it may be annotated with the #[pact(ignore = true)] attribute.

License

Copyright 2024 Alicorn Systems, Inc.

Licensed under the GNU Affero General Public License version 3, as published by the Free Software Foundation. Refer to the license file for more information.

If you have any questions, please reach out to [hello@alicorn.systems].

Dependencies

~4.5MB
~89K SLoC