-
Is there a way we can serialize/deserialize the builder of a struct? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
Hi, today it's possible only to derive Debug and Clone on the builder itself using Could you elaborate a bit more on your use case. I.e. what builder syntax origin are you using (struct, function, associated method), and why would you like to have serde traits derived for the builder (how will this then be used?). I'd like to understand the problem domain on a specific example. Maybe it indeed makes sense to support serde derives on the builder, or maybe not, I just need a bit more context about your specific use case. |
Beta Was this translation helpful? Give feedback.
-
Hey, the use case is for state management with the Teloxide library to build Telegram bots. On each message, the bot parses the text and updates the state enum to another variant (like a FSM). Without Bon, it would look something like this: First wayuse serde::{Deserialize, Serialize};
enum OrderState {
ReceiveItemId,
ReceiveFullName {
item_id: ItemId,
},
ReceiveAddress {
item_id: ItemId,
full_name: Name,
},
ReceiveCreditCardNumber {
item_id: ItemId,
full_name: Name,
address: Address,
},
ReceiveCreditCardPin {
item_id: ItemId,
full_name: Name,
address: Address,
card_number: CardNumber,
},
ConfirmOrder {
item_id: ItemId,
full_name: Name,
address: Address,
card_number: CardNumber,
card_pin: CardPin,
},
}
fn update_state(message: String, state: OrderState) -> OrderState {
match state {
OrderState::ReceiveItemId => OrderState::ReceiveFullName {
item_id: message.parse(),
},
OrderState::ReceiveFullName { item_id } => OrderState::ReceiveAddress {
item_id,
full_name: message.parse(),
},
OrderState::ReceiveAddress { item_id, full_name } => OrderState::ReceiveCardNumber {
item_id,
full_name,
address: message.parse(),
},
// ...etc
}
} Second waystruct OrderBuilder {
item_id: Option<ItemId>,
full_name: Option<Name>,
address: Option<Address>,
card_number: Option<CardNumber>,
card_pin: Option<CardPin>,
}
enum OrderState {
ReceiveItemId,
ReceiveFullName,
ReceiveAddress,
ReceiveCreditCardNumber,
ReceiveCreditCardPin,
ConfirmOrder,
}
fn update_state(message: String, state: OrderState, order: OrderBuilder) -> (OrderState, OrderBuilder) {
match state {
OrderState::ReceiveItemId => (
OrderState::ReceiveFullName,
OrderBuilder{item_id: Some(message.parse()), ..order},
),
OrderState::ReceiveFullName => (
OrderState::ReceiveAddress,
OrderBuilder{full_name: Some(message.parse()), ..order},
),
OrderState::ReceiveAddress => (
OrderState::ReceiveCardNumber,
OrderBuilder{address: Some(message.parse()), ..order},
),
// ...etc
}
} With Bon it would look like this: #[derive(Builder)]
struct Order {
item_id: ItemId,
full_name: Name,
address: Address,
card_number: CardNumber,
card_pin: CardPin,
}
enum OrderState {
ReceiveItemId,
ReceiveFullName,
ReceiveAddress,
ReceiveCreditCardNumber,
ReceiveCreditCardPin,
ConfirmOrder,
}
fn update_state(message: String, state: OrderState, order: OrderBuilder) -> (OrderState, OrderBuilder) {
match state {
OrderState::ReceiveItemId => (
OrderState::ReceiveFullName,
order.item_id(message.parse()),
),
OrderState::ReceiveFullName => (
OrderState::ReceiveAddress,
order.full_name(message.parse()),
),
OrderState::ReceiveAddress => (
OrderState::ReceiveCardNumber,
order.address(message.parse()),
),
// ...etc
}
} However this wouldn't actually compile because Teloxide stores the state in a database between messages, but the builder that Bon generates cannot be serialized. I'm now realizing that Bon implements each builder as a different type so I guess this would not work either way though. |
Beta Was this translation helpful? Give feedback.
Yeah, I don't think
bon
fits this use case, because here you have a complex dynamic type state that should be represented manually.I can suggest a couple of alternative approaches.
An improved "Second way" approach. In this case we don't need an enum of state. The order builder with
Option
fields already delivers enough state info: