-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added TryFrom impl generation for target types behind feature flag #77
Conversation
Accidentally had try_from on unconditionally. Now gated on nightlytests crate feature
@colin-kiegel The failed test looks to be related to a failure in rustup; don't know what to make of that. |
That's rust-lang/rustup#1062 and should be gone with the next nightly release. I can hit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx - good start!
Please merge (or rebase to) current master, because I basically removed the derive_builder_test
crate. All integration tests in derive_builder/tests/
will then need this line:
#![cfg_attr(feature = "try_from", feature(try_from))]
derive_builder/Cargo.toml
Outdated
@@ -23,6 +23,7 @@ proc-macro = true | |||
|
|||
[features] | |||
logging = [ "log", "env_logger", "derive_builder_core/logging" ] | |||
try_from = [] | |||
struct_default = [] | |||
skeptic_tests = ["skeptic"] | |||
nightlytests = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's change this to nightlytests = ["try_from"]
- this will in turn activate it in travis and dev/nightlytests.sh
/ dev/githook.sh
.
BuilderPattern::Mutable | | ||
BuilderPattern::Immutable => quote!(&self), | ||
}; | ||
let self_param = self.pattern.to_build_method_tokens(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to keep this match statement in BuildMethod
for the moment. I feel like from the perspective of unit testing this gives clearer boundaries of responsibility. Of course this makes the BuildMethod
type a little more complex..
derive_builder_core/src/options.rs
Outdated
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please move this back to BuildMethod
for the moment.
derive_builder_core/src/try_from.rs
Outdated
let string_ty = self.bindings.string_ty(); | ||
|
||
let immutable_borrow = quote!( | ||
impl #impl_generics #try_from<&'unused #builder_ty #ty_generics> for #target_ty #ty_generics |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if we elide the lifetime parameter 'unused
and write & #builder_ty #ty_generics
instead?
Would that fail if #ty_generics
contained other lifetime parameters? Did you test that?
If we really need to have an explicit lifetime parameter, I'd suggest to call it 'try_from
just in case so the user would get nicer error messages - while still reducing the risk of name collisions.
derive_builder_core/src/try_from.rs
Outdated
#where_clause { | ||
type Error = #string_ty; | ||
|
||
fn try_from(v: &#builder_ty #ty_generics) -> #result_ty<Self, Self::Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't have a lifetime parameter here, that makes me suspicious that we might not need it. :-)
derive_builder_core/src/try_from.rs
Outdated
|
||
#mutable_borrow | ||
|
||
#owned |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to start with only one impl depending on the builder pattern
Variant 1: Mimic build()
method
Pseudo code for demonstration:
Owned => /* ... impl TryFrom<FooBuilder> for Foo ... */,
Mutable |
Immutable => /* ... impl TryFrom<&FooBuilder> for Foo ... */,
So despite having three variants of BuilderPattern
there would only be two variants of TryFrom
implementations - in analogy to the BuildMethod
.
Variant 2: Always take Self
The logic behind changing the signature of the build method was to enable method chaining FooBuilder::default().foo(1).build()
. But this would most likely not be the primary use case of TryFrom
- although it could be used in this position.
Alternatively we could talk about always implementing TryFrom<FooBuilder> for Foo
and never implementing TryFrom<&FooBuilder> for Foo
.
Discussion
We should probably discuss the primary use cases for having TryFrom
implementations. What signature would they require? Would autoderef or other coercions help to pick the right TryFrom
implementation?
derive_builder_test/Cargo.toml
Outdated
@@ -9,7 +9,7 @@ publish = false | |||
path = "src/lib.rs" | |||
|
|||
[features] | |||
nightlytests = ["compiletest_rs", "derive_builder/nightlytests"] | |||
nightlytests = ["compiletest_rs", "derive_builder/nightlytests", "derive_builder/try_from"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the derive_builder_test
crate in latest master. :-)
PS: More correctly - I merged it into the derive_builder
crate and left a tiny derive_builder/tests/dummy-crate
for doc-inspection.
@@ -0,0 +1,37 @@ | |||
#![cfg(feature = "nightlytests")] | |||
#![cfg_attr(feature = "nightlytests", feature(try_from))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please merge (or rebase to) current master. Then depend on feature = "try_from"
instead.
@colin-kiegel are the run-pass tests not passed the flags from the crate? |
@TedDriggs Hm, it would seem so. You could try something like this for the compiletests. -#![cfg_attr(feature = "nightlytests", feature(try_from))]
+// Compiletests seem to _not_ have access to feature flags. We need to set `#![feature(try_from)]` unconditionally.
+#![allow(unused_features)]
+#![feature(try_from)] |
Now it's complaining about the example in |
includes a workaround for rust-lang/rust#41401
we should not silently implement the `TryFrom` trait if the build function is skipped, because the current `TryFrom` implementation delegates to a build function.
I imagine the final
It's not a problem to start with
What do you think about this? |
PS: If you happen to agree to this change than IMO we would be ready to merge. Otherwise we can of course discuss this more deeply. :-) |
My impression after #54 was that logic should live in inherent methods, with the trait impl being the shallow wrapper.
Without the version that takes a reference, using this in conjunction with #72 gets more verbose. The setter methods are returning let bar = BarBuilder::default()
.try_baz("1.2.3.4")?
.try_foo(FooBuilder::default()
.lorem("Hello")
.ipsum("world"))?
.build()?; I'm not opposed to having an owned, non-cloning implementation, as long as Rust is smart enough to avoid an extra clone to push into that implementation if someone writes the code above. |
Hm, but it does not make a difference with regard to inference whether a trait impl delegates to an inherent method or vice-versa. The main issue in #54 was that things like
I'm actually thinking about changing that default to |
It's already possible to use nested builders even with the mutable pattern. You only need to write I think we can still introduce the Which reminds me that we should raise the minor version with this feature. EDIT: As soon as we remove the feature gate of course. ^^ PS: I'd also welcome more independent opinions on this topic. |
This addresses #76. The generation is automatic but depends on crate feature
try_from
.