pact-derive 0.1.1

Macros for deriving and creating Pacts.
Documentation

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

Generating Rust Types from TOML Pacts

The [macro@pact_toml] macro generates Rust types from a string containing valid Pact TOML:

# use pact_derive::pact_toml;
# use pact::codec::{buffer::*, encode::*, decode::*};

// The annotated string can be an anonymous
// constant like `_`, since it will be replaced
// entirely by the generated code.
#[pact_toml]
const _: &str = r#"
pact = "MyExample"
[entry.1. Request]
message = 'string'
[entry.2. Response]
message = 'string'
"#;

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

// ...and a single enum will be created with
// a variant for each entry in the pact. The
// enum's name will always be the same as the
// pact's name, with `Entry` appended.
let entry = MyExampleEntry::from(request);
assert_eq!("Hello!", match entry {
    MyExampleEntry::Request(Request { message }) => message,
    _ => unimplemented!(),
});

// Both the structs and the enum can code to
// bytes containing pact-coded entries.
# let request = Request { message: "Hello!".into() };
# let entry = MyExampleEntry::from(request.clone());
let request_bytes = EncodedEntry::from(&request).unwrap();
let entry_bytes = EncodedEntry::from(&entry).unwrap();
assert_eq!(request_bytes, entry_bytes);

// The enum can be used to safely code from
// bytes containing pact-coded entries.
let entry = MyExampleEntry::decode_from(&entry_bytes).unwrap();
assert_eq!("Hello!", match entry {
    MyExampleEntry::Request(Request { message }) => message,
    _ => unimplemented!(),
});
# }

Deriving Pact Entry Codecs for Rust Types

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

# use pact_derive::PactCodec;
# use pact::codec::{buffer::*, encode::*, decode::*};

# #[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 be coded to and from
// bytes containing an entry.
let entry_bytes = EncodedEntry::from(&request).unwrap();
let decoded_request = MyRequest::decode_from(&entry_bytes).unwrap();
assert_eq!(request, decoded_request);
# }

If a struct represents an entry in a Pact, an ordinal for the entry 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].