1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//! Port of `UsersTable.c` — htop's uid → username cache.
//!
//! C names are preserved verbatim (htop uses `CamelCase_snake`), so
//! `non_snake_case` is allowed for the whole module — matching the spec
//! name-for-name is the point of the port. Each C function takes
//! `UsersTable* this`; the faithful analog is a free fn taking
//! `this: &mut UsersTable` / `this: &UsersTable`.
//!
//! # C model
//!
//! ```c
//! typedef struct UsersTable_ {
//! Hashtable* users; // uid -> char* username, owning
//! } UsersTable;
//! ```
//!
//! The single field is a `Hashtable` created with `Hashtable_new(10, true)`
//! (`owner == true`): the table owns the `char*` usernames it caches and
//! frees them on removal / teardown. Keys are uids (`ht_key_t` ==
//! `unsigned int`), values are `xStrdup`'d usernames.
//!
//! # Rust model
//!
//! `users` is a `HashMap<u32, String>`, the same choice `table.rs` makes
//! for its `Hashtable* table` field: the ported [`Hashtable`] stores
//! `Box<dyn Object>` values, but a username is a plain `char*`, not an
//! `Object`, so the faithful analog of an OWNING `Hashtable` of strings is
//! a `HashMap` that owns its `String` values — dropping a value *is* the C
//! `owner`-free. The `u32` key is C `ht_key_t` / `unsigned int`; the
//! `String` value is the `xStrdup`'d `pw_name`.
//!
//! [`Hashtable`]: crate::ported::hashtable::Hashtable
//!
//! # Ported
//! - `UsersTable_new` (`UsersTable.c:20`)
//! - `UsersTable_delete` (`UsersTable.c:27`) — `Hashtable_delete(users)` +
//! `free(this)`, a pure teardown. Ported by taking `this` by value
//! (move-in + `Drop` is the C `free`), following the `Hashtable_delete`
//! convention: the moved-in `UsersTable` and its owning `HashMap` drop
//! at end of scope, which is the inner `Hashtable_delete` (owner-free of
//! each cached `String`) plus the outer `free(this)`.
//! - `UsersTable_getRef` (`UsersTable.c:32`)
//! - `UsersTable_foreach` (`UsersTable.c:49`, `inline`)
use HashMap;
/// Port of `typedef struct UsersTable_` from `UsersTable.h:13`. The C
/// `Hashtable* users` (created owning, uid → `char*`) is modeled as an
/// owning `HashMap<u32, String>`: the map owns each cached username and
/// dropping a value is the C `owner`-free (see the module docs).
/// Port of `UsersTable* UsersTable_new(void)` from `UsersTable.c:20`.
/// Allocates the table with an empty user cache. The C
/// `Hashtable_new(10, true)` initial size hint of 10 is carried as the
/// `HashMap`'s reserved capacity; the `owner == true` flag is the map's
/// ownership of its `String` values (see the module docs).
/// Port of `void UsersTable_delete(UsersTable* this)` from
/// `UsersTable.c:27`. Frees the `users` hashtable (C
/// `Hashtable_delete(this->users)`) then frees the struct (C
/// `free(this)`). Taking `this` by value is the faithful analog of
/// `free(this)`, following the [`Hashtable_delete`] port: the moved-in
/// `UsersTable` — and its owning `HashMap<u32, String>`, hence every
/// cached username `String` — drops at end of scope, which *is* the
/// inner `Hashtable_delete` (owner-free of each `char*`) plus the outer
/// `free(this)`.
///
/// [`Hashtable_delete`]: crate::ported::hashtable::Hashtable_delete
/// Port of `char* UsersTable_getRef(UsersTable* this, unsigned int uid)`
/// from `UsersTable.c:32`. Looks up the cached username for `uid`; on a
/// cache miss it resolves the name via `getpwuid` (caching the `pw_name`,
/// or the empty string `""` when the uid is unknown) and stores it. The C
/// returns `NULL` for an empty/unknown name (`if (!name || !*name)`),
/// modeled as `None`, and otherwise a borrowed pointer into the table,
/// modeled as `Some(&str)` borrowing from `this`.
/// Port of `inline void UsersTable_foreach(UsersTable* this,
/// Hashtable_PairFunction f, void* userData)` from `UsersTable.c:49`.
/// Delegates to a walk of the `users` table, calling `f(uid, username)`
/// for every cached entry. The C `Hashtable_PairFunction (ht_key_t, void*,
/// void*)` callback plus its `userData` argument are modeled as a single
/// `&mut dyn FnMut(u32, &str)` closure — user data the C threads through
/// `userData` is captured by the closure instead, exactly as the
/// `Hashtable_foreach` port models the callback+context pair.