Skip to content
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 AllUsers and AllGroups #11

Merged
merged 9 commits into from
Nov 1, 2023

Conversation

OLEGSHA
Copy link
Contributor

@OLEGSHA OLEGSHA commented Sep 24, 2023

AllUsers and AllGroups are traits that provide all_users() and all_groups() similar to how Users and Groups provide other library functions. Also included is UsersSnapshot, a pre-loaded version of UsersCache that can iterate over its contents safely. MockUsers now also implements AllUsers and AllGroups.

Resolves #10.

Example usage

fn old_consumer<U: Users>(u: &U) {
    println!("{:?}", u.get_current_username());
}

fn new_consumer<U: Users + AllUsers>(u: &U) {
    for user in u.get_all_users() { // This call is safe
        println!("{user:?}");
    }
    old_consumer(u);
}

fn main() {
    // The unsafe `all_users` call happens here
    let snapshot = unsafe { UsersSnapshot::new() };
    new_consumer(&snapshot);

    let mut mock = MockUsers::with_current_uid(1234);
    mock.add_user(User::new(1234, "tom", 1234));
    new_consumer(&mock);
}

Checklist:

  • AllUsers
  • AllGroups
  • UsersSnapshot
  • Implement new traits in MockUsers
  • Update docs
  • Add tests

- Renamed `BiMap` to `IdNameMap` to better reflect its purpose
- Extracted type parameters out of `IdNameMap` for ease of reuse
- Added `IdNameMap::insert` for convenience
- `UsersCache` now uses a single `RefCell` for both forward and
  backward maps; does not seem to break anything
- Refactored methods that use `UsersCache::{users,groups}`
  accordingly
- `UsersCache::default` is now implemented with `derive`; `HashMap`
  nonsense moved into the new `IdNameMap::default`
- Added `AllUsers` trait that provides `all_users()`
- Added `UsersSnapshot`
  - user data is pre-loaded, not fetched lazily
  - implements `AllUsers` and `Users`
- `MockUsers` now implements `AllUsers` exposing the list of added
  users
- Equivalent group functionality NYI
- Documentation not yet updated
@OLEGSHA
Copy link
Contributor Author

OLEGSHA commented Sep 24, 2023

I have stopped short of writing the groups code and updating docs because I'm not entirely sure this is the correct approach.

An alternative implementation exists in make-iters-mockable, where AllUsers includes Arc-less versions of all Users methods (get_user_by_uid -> Option<Arc<User>> becomes user_by_uid -> Option<&User>). Using AllUsers then reduces dynamic memory allocations significantly. However, this is not backwards-compatible with Users; attempting to implement Users in UsersSnapshot results in memory allocations in getters, which is definitely bad.

So I decided to design UsersSnapshot around the Users trait instead. This means Arcs are stored in the hashmap for no real reason.

Finally, I don't really like the name collision with the private return type of all_users() function.

Please let me know what you think, and I'll finish the PR then.

@gierens
Copy link
Member

gierens commented Oct 1, 2023

Please let me know what you think, and I'll finish the PR then.

Sorry, for the late response, have been busy lately and I knew this would take a moment to read through properly ... especially with the two options.

Anyway, this look very promising to me in general, thank you!

I have stopped short of writing the groups code and updating docs because I'm not entirely sure this is the correct approach.

An alternative implementation exists in make-iters-mockable

Hm, comparing both I gotta say the "dryer" version here looks a lot cleaner to me or much easier to understand at the very least. I'm not sure the potential performance benefits of the other version are worth the over-complication it introduces in the AllUsers trait. So I would continue with the version here.

- Added `AllGroups` trait that provides `all_groups()`
- `UsersSnapshot` now implements `Groups` and `AllGroups`
- `MockUsers` now implements `AllGroups`
- `UsersSnapshot::filtered` not yet updated: adds all groups
- Documentation not yet updated
`UsersSnapshot::filtered` has been split into two new methods to
accomodate the two probable use cases:
- `::filtered` now accepts a separate filter for groups
- `::only_users` only accepts groups that are some included user's
  primary group.
- Documentation of `UsersCache` was moved from module to the struct
  itself to keep the module doc from bloating to a billion lines.
- Description of `UsersCache` in crate doc shortened slightly as it
  is no longer the only solution.
@OLEGSHA OLEGSHA marked this pull request as ready for review October 19, 2023 16:16
@OLEGSHA
Copy link
Contributor Author

OLEGSHA commented Oct 20, 2023

UsersCache::with_all_users() becomes confusing and largely unnecessary with this PR. A GitHub-wide search shows there is barely any use of this method, certainly none where the transition to UsersSnapshot should be bad. I think it's safe to deprecate it.

Copy link
Member

@gierens gierens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very sorry it took me so long to get back to you! ... Again, thanks! LGTM! ... I added a deprecation warning to UsersCache::with_all_users() for the upcoming minor version and reworded one of the commit messages a little. With that it should be ready for merge now!

@gierens gierens merged commit 66d2762 into rustadopt:main Nov 1, 2023
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make all_users mockable
2 participants