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
Config access uses impl Key
to allow type-safe keys
#1236
base: main
Are you sure you want to change the base?
Conversation
impl Key
to allow structured keysimpl Key
to allow type-safe keys
gix-config/src/file/access/raw.rs
Outdated
Ok(section.set(key.try_into().map_err(section::key::Error::from)?, new_value.into())) | ||
) -> Result<Option<Cow<'event, BStr>>, crate::file::set_raw_value::Error> { | ||
let mut section = self.section_mut_or_create_new_filter(key.section_name(), key.subsection_name(), filter)?; | ||
let key = key.name().to_owned().try_into().map_err(section::key::Error::from)?; // TODO Borrow, plz |
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.
This to_owned()
is not optimal, but it is not obvious to me how to formulate the required lifetimes.
match ((&input).section_name(), (&input).subsection_name()) { | ||
(section, subsection) if !section.is_empty() => Filter { | ||
name: section.into(), | ||
subsection: subsection.map(ToOwned::to_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'm not sure exactly how the filter is used, so I'm not 100% sure this change retains the exact behavior of the filter in all corner cases.
key: impl AsRef<str>, | ||
) -> Option<Cow<'_, BStr>> { | ||
self.string_filter(section_name, subsection_name, key, &mut |_| true) | ||
pub fn string<'a>(&self, key: impl Key<'a>) -> Option<Cow<'_, BStr>> { |
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.
Should we rename these lifetimes to `'lookup'?
gix-config/src/traits.rs
Outdated
/// Parsed elements of a Git config key, like `remote.origin.url` or `core.bare`. | ||
pub trait Key<'a> { | ||
/// The name of the section key, like `url` in `remote.origin.url`. | ||
fn name(&self) -> &'a str; |
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.
Is name()
to generic given that we implement it on &[b]str
? .key_name()
might be better?
gix-config/src/file/access/raw.rs
Outdated
.rev(); | ||
let key = section::Key(Cow::<BStr>::Borrowed(key.into())); | ||
let key = section::Key(Cow::Borrowed(key.name().into())); // TODO Borrow, plz |
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.
Oops, this TODO is already addressed.
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.
Thanks for sharing your amazing progress!
Before I can look at anything in detail, I'd need the commits split up so that…
- …the
Key
related changes ingix-config
are in one commit, whose subject is prefixed withfix!:
orfeat!:
. Please write the subject and body so they can go into the changelog. - …all other changes to adapt to this change can go into its own commit without any special message requirements.
There is also this one big request of only modifying the string_by_key
based access with the new trait. After all, the natural way of accessing the API is by passing triplets of section, subsection and 'key' (definitely open to a better term here).
That way, only string_by_key()
has to change at all and that change would probably be compatible to most existing uses depending on the available implementations of Key
for &BStr
for example. I don't think there is a need to break the world here, and hope this could even work without making any breaking change.
Is that feasible at all?
Is the purpose simply to have a
I was thinking we should keep the API surface small by removing all the |
No, the purpose is to have a changelog that applies to the That takes priority over each commit being green on CI, it's all trade-offs.
Thanks for sharing your thoughts. For a plumbing crate, it would already be more than fine. However, it's exposed in But since you would be touching all of these methods anyway, let's encourage the use of the potentially typesafe and nicer API by making their methods the shorter ones. This means, for example, to keep I hope all that makes sense, please do let me know about any concern you might have as well. |
f1d7e94
to
00f7c28
Compare
86e5f83
to
819d7eb
Compare
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.
Thanks so much for the changes!
It's wonderful to see how the standard-API of gix-config
can be enhanced by the Key
trait. While looking at it more closely, I also noticed something else that I think can be fixed without too much overhead.
But if that work should ever appear overwhelming or boring because the API surface is quite massive, please let me know and I can help doing the refactoring. The last thing I'd want is for you to get exhausted due to all these comments of mine 😅.
Just let me know how I can help and I will try to make it happen.
Thanks again!
|
||
use crate::traits::Key; | ||
|
||
impl Key for &String { |
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.
Now that I see it, the way Key
is designed requires some duplicate work. In order to make any call to one of the *_by(section, subsection, key)
methods, one will have to do extra work in order to get the subsection name, even though what one is really doing is to split a string across .
two or three times.
That operation, along with the potential for failure, are already captured in parse::key()
. Thus Key
would probably be better named ParseKey
while providing only one method to obtain a parse::Key
.
Doing this would probably also do away with the duplication in implementation, as it then all boils down to getting a &BStr
for parsing a key.
|
||
assert_eq!("", "foo".section_name()); | ||
assert_eq!(None, "foo".subsection_name()); | ||
assert_eq!("foo", "foo".name()); |
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.
Related to my earlier comment, this is a good example on where the API of Key
isn't currently suitable to capture what a Key
is. Top-level keys like "foo"
are not valid, they need a section name, and empty section names are not permitted (nor are empty keys).
Thus I think it's important to be able to express a parsing failure or 'invalid key' as part of the Key
trait (or ParseKey
trait as proposed).
As a note, I plan to finish this PR myself once I get a chance. |
This PR changes the API of
gix_config::File
to use a trait (gix_config::Key) as key when requesting or setting configuration. This will allowgix
to use its tree of structured and validating typed keys (gix::config::tree::sections::*
) as keys directly, and also means that consumers of thegix
crate to use type-safe config access. gix-config also provides an implementation for &str and &bstr so that constant strings can be used as keys. This is part of the work addressing #1125.The PR is draft, as there remains various question marks, see specific comments in code below.
gix contains a lot of strings and
format!()
operations that could be changed to use type-safe keys, but that is left for a separate PR.