-
Notifications
You must be signed in to change notification settings - Fork 67
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
Add functions to access existing modules in a scope #1
Conversation
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This reverts commit 50b7156.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
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 the PR.
I think the best option is to try to stick to simple. Lookup performance isn't really a huge factor here, so a sequential scan to find modules is a-ok I think. I have added some thoughts inline.
Re: naming:
If there is a _mut
variant, there probably should be one that is immutable too. To avoid fn names that conflict with Rust keywords, a get_
prefix is probably a good idea.
So, get_module
and get_module_mut
it is!
src/lib.rs
Outdated
/// Modules are stored in a map rather than in this scope's | ||
/// `items` vector so that they may be accessed by name directly | ||
/// after being created. | ||
modules: OrderMap<RcKey, Module>, |
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 would not bother with this, instead doing a scan of items
to find a module. Again, lookup performance isn't really a factor at this point.
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.
Hmm, my initial implementation did a scan through items
, but I ended up going with this approach because i found it to be simpler (esp. given the borrow-checker gymnastics that ended up being necessary to make module_or_add
work).
src/lib.rs
Outdated
/// to index the scope's map of modules. This way, modules can be looked up | ||
/// by name, but also are defined at ordered locations in the `items` | ||
/// vector. | ||
Module(Rc<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.
I'd probably revert this.
src/lib.rs
Outdated
@@ -231,12 +251,20 @@ pub struct Formatter<'a> { | |||
dst: &'a mut String, | |||
|
|||
/// Number of spaces to start a new line with | |||
/// |
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.
Extra line?
src/lib.rs
Outdated
@@ -57,7 +77,7 @@ enum Item { | |||
#[derive(Debug, Clone)] | |||
pub struct Module { | |||
/// Module name | |||
name: String, | |||
name: Rc<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.
I'd revert this.
src/lib.rs
Outdated
@@ -262,19 +291,62 @@ impl Scope { | |||
.or_insert_with(|| Import::new(path, ty)) | |||
} | |||
|
|||
/// Returns true if a module named `name` exists in this scope. | |||
pub fn contains_module<Q: ?Sized>(&self, name: &Q) -> bool |
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.
We probably don't need this function right now. I would stick with get_module
and get_module_mut
. These functions return Option
so you can just do if scope.get_module("name").is_some()
.
Again, we can re-evaluate later if it ends up sucking.
src/lib.rs
Outdated
/// In many cases, the [`module_or_add`] function is preferrable, as it will | ||
/// return the existing definition instead. | ||
/// | ||
/// [`module_or_add`]: #method.module_or_add | ||
pub fn push_module(&mut self, item: Module) -> &mut Self { |
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 probably should panic if called and there already is a module with the same name in the scope.
src/lib.rs
Outdated
|
||
/// Returns a mutable reference to a module, creating it if it does | ||
/// not exist. | ||
pub fn module_or_add(&mut self, name: &str) -> &mut Module { |
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 get rid of this for now. The check can be done w/ other functions.
If this becomes a pattern, then we can look at all the instances (modules, structs, etc...) and see if we can come up with a good 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.
Hmm...I opened the PR with the primary goal of adding this function specifically, because I needed it in my changes to tower-grpc
(get_module
and get_module_mut
were added only because it was more or less trivial to add them as well while making this change), and currently, it's the only one of these functions that's currently used in a consumer of codegen
(my branch of tower-grpc
).
While it's certainly possible to remove this & rewrite the functions that use it, I think that code is a bit clearer with this function, and my suspicion is that it's it's likely to be the most common use-case for retrieving a module...
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 module_mut
has been renamed to get_module_mut
(299c69a), what about renaming this to just module
, by analogy with import
, which also has similar "get or else add" behavior?)
src/lib.rs
Outdated
} | ||
|
||
/// Returns a mutable reference to a module if it is exists in this scope. | ||
pub fn module_mut(&mut self, name: &str) -> Option<&mut Module> { |
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 probably should be renamed get_module_mut
to match get_module
.
- Remove `contains_module` - Rename `module_mut` -> `get_module_mut` - Add `get_module` - Make `get_module`/`get_module_mut` generic over key type. Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
@carllerche sorry I didn't comment earlier; I've made a majority of the changes you've requested. I disagree with your comment that the function formally called |
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.
Some thoughts left inline.
src/lib.rs
Outdated
/// to index the scope's map of modules. This way, modules can be looked up | ||
/// by name, but also are defined at ordered locations in the `items` | ||
/// vector. | ||
Module(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.
I'd rather avoid the additional indirection for now.
If doing a sequential scan in the lookup fns is problematic, we can explore replacing items: Vec<Item>
with an OrderMap
as order is preserved with that structure as well. This probably should happen in a separate PR.
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.
Replacing items
with an OrderMap
was the second approach I tried (50b7156), it turned out to be problematic as not all items had obvious keys into that map, and it was difficult to determine keys that wouldn't result in some items being clobbered when they shouldn't be. I'll take another crack at the sequential scan instead.
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.
Okay, done in 71348a8.
src/lib.rs
Outdated
|
||
/// Returns a mutable reference to a module, creating it if it does | ||
/// not exist. | ||
pub fn get_or_add_module(&mut self, name: &str) -> &mut Module { |
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.
Could this be named get_or_new_module
in this PR?
I agree the new
terminology is not ideal, but that is the convention currently used for all other fns. We can approach improving the naming scheme in another PR.
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.
Sure, changed it back in 3824853.
This reverts commit d64445d.
@carllerche, I think I've made all the changes you requested. |
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!
One last relatively minor thought.
Also, if you want to pursue the new
rename, I'd recommend opening an issue w/ a proposal so we can bikeshed the naming!
src/lib.rs
Outdated
String: PartialEq<Q>, | ||
{ | ||
self.items.iter_mut() | ||
.find(|item| if let &mut Item::Module(ref module) = *item { |
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.
The find(...).map(...)
sequence could probably be replaced by filter_map(...).next()
to avoid having to match twice.
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 thought about that when implementing this originally, and then forgot. Changed in b40b1e6.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Remove travis-ci, add gitlab ci Closes #1 See merge request IovoslavIovchev/codegen!5
While working on tower-rs/tower-grpc#9, I found that I sometimes had the need to access a module by name when it had previously been created in a given scope.
Changes
I've added the following new functions on the
Scope
andModule
types:module_mut
optionally returns&mut Module
if a scope contains a module with the given name.module_or_add
returns&mut Module
if a scope contains a module with the given name, or creates it and returns a mut reference to it if it does not yet exist.contains_module
returns true if a scope contains a module with the given name.I've also added a handful of unit tests for
module_mut
andmodule_or_add
.After experimenting with a number of ways to implement this functionality, I settled on storing the
Module
s defined in aScope
in anOrderMap
separate from the scope'sitems
vec. I changedItem::Module
so that, rather than owning theModule
, it stores the name of the module so that when theitems
vector is iterated over, it can access the module by looking it up in themodules
map. The names ofModule
s are now reference counted, so that we can reuse the same string for the name stored in theModule
struct itself, the key in themodules
map, and the key stored inItem::Module
.Questions
module_or_add
is the best name for the "return a module if it exists, or else create it" method, but couldn't come up with a better one. If anyone could think of a name that better describes the function's behaviour without being overly verbose, that would be greatly appreciated. (I considered just calling itmodule
but thought that might conflict with a hypothetical function to get a module by name non-mutably...)module_mut
. If so, what should it (and the method currently namedmodule_mut
) be called ---module
/module_mut
?get_module
/get_module_mut
?