Summary
Limits is the only runtime-config type in the crate whose setters are bare verbs rather than with_-prefixed, and it is also the only one that exposes public fields alongside those setters — with the field and the method sharing an identifier.
// connectrpc/src/service.rs
#[non_exhaustive]
pub struct Limits {
pub max_request_body_size: usize,
pub max_message_size: usize,
pub element_memory_limit: usize,
}
impl Limits {
pub fn max_request_body_size(mut self, size: usize) -> Self { ... }
pub fn max_message_size(mut self, size: usize) -> Self { ... }
pub fn element_memory_limit(mut self, bytes: usize) -> Self { ... }
}
Every sibling config type uses with_: ConnectRpcService::with_limits / with_compression, ClientConfig::with_protocol / with_default_timeout, Server::with_*, RequestContext::with_*. There are 81 with_-prefixed setters in the crate and three that are not, all three on this type.
Why it matters
A user who has learned with_ on the service and the client reaches for limits.with_max_message_size(..), gets method-not-found, and has to read the source to discover the bare name. That is a small cost, but it is paid by every user exactly once at the point where they are hardening a server, and it is avoidable.
The overlap with the fields is the sharper problem. Because the fields are pub and the methods share their names, there are two ways to set each value; and because the struct is #[non_exhaustive], struct-update syntax does not work anyway, so the public fields buy construction flexibility that the attribute has already removed. What they do buy is field reads, which accessors would cover.
ClientConfig is the shape to copy: private fields, with_ setters, plain accessors, #[non_exhaustive], and a doc note about the struct-update limitation.
Proposal
- Rename the three setters to
with_max_request_body_size, with_max_message_size, with_element_memory_limit.
- Make the three fields private and add accessors returning
usize.
Both are breaking, which is why this belongs in the 0.9.0 window rather than after it.
Item 1 alone is the higher-value half; item 2 is worth taking at the same time so the type is only broken once, but is separable if there is disagreement about it.
Notes
Related to #173 (rejecting illegal values in configuration setters) in that both are about making the setter surface consistent, but the changes do not overlap — that issue is about validation behaviour, this one is about naming and field visibility.
Summary
Limitsis the only runtime-config type in the crate whose setters are bare verbs rather thanwith_-prefixed, and it is also the only one that exposes public fields alongside those setters — with the field and the method sharing an identifier.Every sibling config type uses
with_:ConnectRpcService::with_limits/with_compression,ClientConfig::with_protocol/with_default_timeout,Server::with_*,RequestContext::with_*. There are 81with_-prefixed setters in the crate and three that are not, all three on this type.Why it matters
A user who has learned
with_on the service and the client reaches forlimits.with_max_message_size(..), gets method-not-found, and has to read the source to discover the bare name. That is a small cost, but it is paid by every user exactly once at the point where they are hardening a server, and it is avoidable.The overlap with the fields is the sharper problem. Because the fields are
puband the methods share their names, there are two ways to set each value; and because the struct is#[non_exhaustive], struct-update syntax does not work anyway, so the public fields buy construction flexibility that the attribute has already removed. What they do buy is field reads, which accessors would cover.ClientConfigis the shape to copy: private fields,with_setters, plain accessors,#[non_exhaustive], and a doc note about the struct-update limitation.Proposal
with_max_request_body_size,with_max_message_size,with_element_memory_limit.usize.Both are breaking, which is why this belongs in the 0.9.0 window rather than after it.
Item 1 alone is the higher-value half; item 2 is worth taking at the same time so the type is only broken once, but is separable if there is disagreement about it.
Notes
Related to #173 (rejecting illegal values in configuration setters) in that both are about making the setter surface consistent, but the changes do not overlap — that issue is about validation behaviour, this one is about naming and field visibility.