Macros for generating Rust types from TOML Pacts, and deriving [Pact](https://crates.io/crates/pact) codecs for Rust types. ## _Generating_ Rust Types from TOML Pacts The [`pact_toml`](macro@pact_toml) macro generates Rust types from a string containing a Pact TOML: ```rust # 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)`](derive_pact_codec) macro derives a pact codec (encoder and decoder) for a Rust struct: ```rust # 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](../LICENSE.txt) for more information. If you have any questions, please reach out to [`hello@alicorn.systems`].