Skip to content

Commit

Permalink
WIP: Replace builder to improve ergonomics (#66)
Browse files Browse the repository at this point in the history
Co-authored-by: Zachary Vacura <[email protected]>
  • Loading branch information
Hackzzila and Zachary Vacura authored Jul 30, 2024
1 parent 2388b1e commit 3cfda9a
Show file tree
Hide file tree
Showing 163 changed files with 14,598 additions and 3,184 deletions.
32 changes: 0 additions & 32 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ snap = "1.0.5"
flate2 = "1.0.20"
zstd = "0.13"
lz4 = "1.24"
derive_builder = "0.20.0"
paste = "1.0.7"
crc32c = "0.6.4"
anyhow = "1.0.80"
Expand Down
26 changes: 12 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Protocol messages are generated against a recent stable Kafka release, currently

Although the Kafka protocol remains relatively stable and strives to be backwards compatible, new fields are occasionally
added. In order to ensure forward compatibility with the protocol, this crate marks all exported items as `#[non-exhaustive]`.
Protocol messages can be constructed using either `Default::default` or their provided [builder](https://docs.rs/derive_builder/latest/derive_builder/).
Protocol messages can be constructed using `Default::default` and updated with builder style methods.

## Working with messages

Expand All @@ -31,21 +31,19 @@ request.topics = None;
request.allow_auto_topic_creation = true;
```

Using `kafka_protocol::protocol::Builder`:
Using builder style methods:
```rust
use kafka_protocol::messages::{ApiKey, MetadataRequest, RequestHeader};
use kafka_protocol::protocol::{Builder, StrBytes};

let header = RequestHeader::builder()
.client_id(Some(StrBytes::from_static_str("my-client")))
.request_api_key(ApiKey::MetadataKey as i16)
.request_api_version(12)
.build();
!
let request = MetadataRequest::builder()
.topics(None)
.allow_auto_topic_creation(true)
.build();
use kafka_protocol::protocol::StrBytes;

let header = RequestHeader::default()
.with_client_id(Some(StrBytes::from_static_str("my-client")))
.with_request_api_key(ApiKey::MetadataKey as i16)
.with_request_api_version(12);

let request = MetadataRequest::default()
.with_topics(None)
.with_allow_auto_topic_creation(true);
```
### Serialization

Expand Down
79 changes: 63 additions & 16 deletions protocol_codegen/src/generate_messages/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1083,11 +1083,7 @@ impl PreparedStruct {
pub fn apply<W: Write>(&self, w: &mut CodeWriter<W>) -> Result<(), Error> {
writeln!(w, "/// Valid versions: {}", self.valid_versions)?;
writeln!(w, "#[non_exhaustive]")?;
writeln!(
w,
"#[derive(Debug, Clone, PartialEq, derive_builder::Builder)]"
)?;
writeln!(w, "#[builder(default)]")?;
writeln!(w, "#[derive(Debug, Clone, PartialEq)]")?;
write!(w, "pub struct {} ", self.name)?;
w.block(|w| {
for prepared_field in &self.prepared_fields {
Expand Down Expand Up @@ -1125,16 +1121,67 @@ impl PreparedStruct {
writeln!(w)?;
writeln!(w)?;

write!(w, "impl Builder for {} ", self.name)?;
write!(w, "impl {} ", self.name)?;
w.block(|w| {
writeln!(w, "type Builder = {}Builder;", self.name)?;
writeln!(w)?;
write!(w, "fn builder() -> Self::Builder")?;
w.block(|w| {
writeln!(w, "{}Builder::default()", self.name)?;
Ok(())
})?;
writeln!(w)?;
for prepared_field in &self.prepared_fields {
if prepared_field.map_key {
continue;
}

writeln!(w, "/// Sets `{}` to the passed value.", prepared_field.name)?;
writeln!(w, "/// ")?;
writeln!(w, "/// {}", prepared_field.about)?;
writeln!(w, "/// ")?;
writeln!(w, "/// Supported API versions: {}", prepared_field.versions)?;
if prepared_field.optional {
writeln!(
w,
"pub fn with_{}(mut self, value: Option<{}>) -> Self",
prepared_field.name.trim_start_matches('_'),
prepared_field.type_.rust_name()
)?;
} else {
writeln!(
w,
"pub fn with_{}(mut self, value: {}) -> Self",
prepared_field.name.trim_start_matches('_'),
prepared_field.type_.rust_name()
)?;
}

w.block(|w| {
writeln!(w, "self.{} = value;", prepared_field.name)?;
writeln!(w, "self")?;
Ok(())
})?;
}

if !self.flexible_msg_versions.is_none() {
writeln!(w, "/// Sets unknown_tagged_fields to the passed value.")?;
writeln!(
w,
"pub fn with_unknown_tagged_fields(mut self, value: BTreeMap<i32, Bytes>) -> Self"
)?;
w.block(|w| {
writeln!(w, "self.unknown_tagged_fields = value;")?;
writeln!(w, "self")?;

Ok(())
})?;

writeln!(w, "/// Inserts an entry into unknown_tagged_fields.")?;
writeln!(
w,
"pub fn with_unknown_tagged_field(mut self, key: i32, value: Bytes) -> Self"
)?;
w.block(|w| {
writeln!(w, "self.unknown_tagged_fields.insert(key, value);")?;
writeln!(w, "self")?;

Ok(())
})?;
}

Ok(())
})?;
writeln!(w)?;
Expand Down Expand Up @@ -1308,8 +1355,8 @@ fn write_file_header<W: Write>(w: &mut CodeWriter<W>, name: &str) -> Result<(),
writeln!(w, "use anyhow::{{bail, Result}};")?;
writeln!(w)?;
writeln!(w, "use crate::protocol::{{")?;
writeln!(w, " Encodable, Decodable, MapEncodable, MapDecodable, Encoder, Decoder, Message, HeaderVersion, VersionRange,")?;
writeln!(w, " types, write_unknown_tagged_fields, compute_unknown_tagged_fields_size, StrBytes, buf::{{ByteBuf, ByteBufMut}}, Builder")?;
writeln!(w, " Encodable, Decodable, MapEncodable, MapDecodable, Encoder, Decoder, Message, HeaderVersion, VersionRange,")?;
writeln!(w, " types, write_unknown_tagged_fields, compute_unknown_tagged_fields_size, StrBytes, buf::{{ByteBuf, ByteBufMut}}")?;
writeln!(w, "}};")?;
writeln!(w)?;
writeln!(w)?;
Expand Down
59 changes: 49 additions & 10 deletions src/messages/add_offsets_to_txn_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ use uuid::Uuid;

use crate::protocol::{
buf::{ByteBuf, ByteBufMut},
compute_unknown_tagged_fields_size, types, write_unknown_tagged_fields, Builder, Decodable,
Decoder, Encodable, Encoder, HeaderVersion, MapDecodable, MapEncodable, Message, StrBytes,
VersionRange,
compute_unknown_tagged_fields_size, types, write_unknown_tagged_fields, Decodable, Decoder,
Encodable, Encoder, HeaderVersion, MapDecodable, MapEncodable, Message, StrBytes, VersionRange,
};

/// Valid versions: 0-3
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, derive_builder::Builder)]
#[builder(default)]
#[derive(Debug, Clone, PartialEq)]
pub struct AddOffsetsToTxnRequest {
/// The transactional id corresponding to the transaction.
///
Expand All @@ -47,11 +45,52 @@ pub struct AddOffsetsToTxnRequest {
pub unknown_tagged_fields: BTreeMap<i32, Bytes>,
}

impl Builder for AddOffsetsToTxnRequest {
type Builder = AddOffsetsToTxnRequestBuilder;

fn builder() -> Self::Builder {
AddOffsetsToTxnRequestBuilder::default()
impl AddOffsetsToTxnRequest {
/// Sets `transactional_id` to the passed value.
///
/// The transactional id corresponding to the transaction.
///
/// Supported API versions: 0-3
pub fn with_transactional_id(mut self, value: super::TransactionalId) -> Self {
self.transactional_id = value;
self
}
/// Sets `producer_id` to the passed value.
///
/// Current producer id in use by the transactional id.
///
/// Supported API versions: 0-3
pub fn with_producer_id(mut self, value: super::ProducerId) -> Self {
self.producer_id = value;
self
}
/// Sets `producer_epoch` to the passed value.
///
/// Current epoch associated with the producer id.
///
/// Supported API versions: 0-3
pub fn with_producer_epoch(mut self, value: i16) -> Self {
self.producer_epoch = value;
self
}
/// Sets `group_id` to the passed value.
///
/// The unique group identifier.
///
/// Supported API versions: 0-3
pub fn with_group_id(mut self, value: super::GroupId) -> Self {
self.group_id = value;
self
}
/// Sets unknown_tagged_fields to the passed value.
pub fn with_unknown_tagged_fields(mut self, value: BTreeMap<i32, Bytes>) -> Self {
self.unknown_tagged_fields = value;
self
}
/// Inserts an entry into unknown_tagged_fields.
pub fn with_unknown_tagged_field(mut self, key: i32, value: Bytes) -> Self {
self.unknown_tagged_fields.insert(key, value);
self
}
}

Expand Down
41 changes: 31 additions & 10 deletions src/messages/add_offsets_to_txn_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ use uuid::Uuid;

use crate::protocol::{
buf::{ByteBuf, ByteBufMut},
compute_unknown_tagged_fields_size, types, write_unknown_tagged_fields, Builder, Decodable,
Decoder, Encodable, Encoder, HeaderVersion, MapDecodable, MapEncodable, Message, StrBytes,
VersionRange,
compute_unknown_tagged_fields_size, types, write_unknown_tagged_fields, Decodable, Decoder,
Encodable, Encoder, HeaderVersion, MapDecodable, MapEncodable, Message, StrBytes, VersionRange,
};

/// Valid versions: 0-3
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, derive_builder::Builder)]
#[builder(default)]
#[derive(Debug, Clone, PartialEq)]
pub struct AddOffsetsToTxnResponse {
/// Duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota.
///
Expand All @@ -37,11 +35,34 @@ pub struct AddOffsetsToTxnResponse {
pub unknown_tagged_fields: BTreeMap<i32, Bytes>,
}

impl Builder for AddOffsetsToTxnResponse {
type Builder = AddOffsetsToTxnResponseBuilder;

fn builder() -> Self::Builder {
AddOffsetsToTxnResponseBuilder::default()
impl AddOffsetsToTxnResponse {
/// Sets `throttle_time_ms` to the passed value.
///
/// Duration in milliseconds for which the request was throttled due to a quota violation, or zero if the request did not violate any quota.
///
/// Supported API versions: 0-3
pub fn with_throttle_time_ms(mut self, value: i32) -> Self {
self.throttle_time_ms = value;
self
}
/// Sets `error_code` to the passed value.
///
/// The response error code, or 0 if there was no error.
///
/// Supported API versions: 0-3
pub fn with_error_code(mut self, value: i16) -> Self {
self.error_code = value;
self
}
/// Sets unknown_tagged_fields to the passed value.
pub fn with_unknown_tagged_fields(mut self, value: BTreeMap<i32, Bytes>) -> Self {
self.unknown_tagged_fields = value;
self
}
/// Inserts an entry into unknown_tagged_fields.
pub fn with_unknown_tagged_field(mut self, key: i32, value: Bytes) -> Self {
self.unknown_tagged_fields.insert(key, value);
self
}
}

Expand Down
Loading

0 comments on commit 3cfda9a

Please sign in to comment.