Conversation
Empathy is an Oxide value!
Initial thoughts: progenitor has not had as a goal generation of clippy-clean code. There's a good reason for that! Clippy is intended for code written by humans. Or written by LLMs and read by humans? For example, we would prefer a human (or LLM) write My thought in this case is--I think?--the same as the strawman above. Also, this is--I assume--an example of clippy uncleanliness that you encountered, but there are others that you didn't. If the goal is to make generated code clippy-clean, how thorough would we want to be? How would we want to build out the testing framework to ensure clippy-cleanliness? More specifically, I worry about future changes (e.g. by me!) forgetting to add to this "is it So those are my thoughts. I hope that can be the start of a discussion; they're not intended as an edict--just the basis on why we are where we are. |
This makes some sense. In this case the Clippy warnings are harmless, and like your
I think generating clippy-clean code is potentially a worthy goal. I have not done an audit of projects/repos that depend on progenitor to identify scope of effort -- my projects have only triggered one Clippy lint ( After writing the above paragraph, that is the direction I've decided to go with. No changes to progenitor and I get cleaner code. Created an issue for tracking this idea going forward: |
This is my first time wading into the progenitor code. Please be kind!
Background
Previously, progenitor generated code that would be conservative and always
.clone():progenitor/progenitor-impl/src/cli.rs
Lines 430 to 438 in 1a5b88f
If you ran generated code through Clippy you'd see lots of these:
Workaround
Inject a
#[allow(clippy::redundant_clone)]at the top of each generated file.It worked in: https://github.com/oxidecomputer/four-star/pull/322
But that's a little ugly.
Solution
Enumerate all the cases where we don't have to clone.
TypeDetailsTypeDetails::Unit(e.g.())*valueTypeDetails::Builtin(bool)*valueTypeDetails::Builtin({i8,i16,i32,i64,u8,u16,u32,u64})*valueTypeDetails::Builtin(::std::num::NonZeroU{8,16,32,64})*valueTypeDetails::Builtin(...)forf32,f64*valueTypeDetails::Builtin(::uuid::Uuid)*valueTypeDetails::Builtin(::chrono::naive::NaiveDate)*valueTypeDetails::Builtin(::chrono::DateTime<::chrono::offset::Utc>)*valueTypeDetails::Builtin(::std::net::IpAddr)*valueTypeDetails::Builtin(::std::net::Ipv4Addr)*valueTypeDetails::Builtin(::std::net::Ipv6Addr)*valueTypeDetails::Enum(...)where all variants are simple*valueTypeDetails::Stringvalue.as_str()TypeDetails::StringforTryInto<Option<String>>value.clone()TypeDetails::Enum(...)for data-carrying enumsvalue.clone()TypeDetails::Builtin(::serde_json::Value)value.clone()TypeDetails::Builtin(...)for any Builtin not listed abovevalue.clone()TypeDetails::Struct(...)value.clone()TypeDetails::Newtype(...)value.clone()TypeDetails::Option(_)forOption<T>value.clone()TypeDetails::Vec(_)forVec<T>value.clone()TypeDetails::Map(_, _)forBTreeMap<K, V>or map equivalentvalue.clone()TypeDetails::Set(_)for set typesvalue.clone()TypeDetails::Box(_)forBox<T>value.clone()TypeDetails::Tuple(_)for tuple types, e.g.(A, B)value.clone()TypeDetails::Array(_, _)for array types, e.g.[T; N]value.clone()TypeDetailsvariantvalue.clone()Impact
If progenitor generates code which passes clippy out-of-the-box, it's easier for dependent projects to run clippy without having to create exemptions for generated code.
I tried this on four-star, and it went from 17 clippy warnings on the generated code to 0.
Here's the diff when run using this branch.
This should have nominal impact on generation times.
I would not expect any runtime performance impact (positive or negative).
I'm pretty sure the Rust compiler will yield similar output either way.
Thoughts?
Tests
Probably worth setting up test(s) with all the types above plus a custom TypeDetails variant and assert they are all handled as expected.
Discussion
There is some complexity here and I'm not sure the juice is worth the squeeze. A naive alternative would just emit
#[allow(clippy::redundant_clone)]for these files or each of these functions (whether it has redundant clones or not).