Skip to main content

zsh/ported/zle/
compctl_h.rs

1//! `compctl.h` port — completion descriptor types + `CC_*` / `CCT_*`
2//! flag constants used by the legacy `compctl` builtin.
3//!
4//! Port of `Src/Zle/compctl.h`. Canonical home for the four typedefs
5//! (`Compctlp`/`Compctl`/`Compcond`/`Patcomp`) and the two flag-bit
6//! families: 30 `CC_*` primary completion-target flags (mask) and 7
7//! `CC_*` secondary flags (mask2), plus 14 `CCT_*` `-x` condition
8//! types.
9//!
10//! C source: 4 typedefs + 4 structs (`compctlp`, `patcomp`,
11//! `compcond`, `compctl`), 14 `CCT_*` constants (c:76-89), 30
12//! primary `CC_*` constants (c:118-149), 7 secondary `CC_*` constants
13//! (c:152-158). 0 functions.
14//!
15//! `compctl.rs` (the .c port) re-exports these via `pub use
16//! super::compctl_h::*;` so existing `cc_flags::FILES` / `cct::POS`
17//! call sites keep compiling alongside the C-canonical
18//! `CC_FILES` / `CCT_POS` names.
19
20// ---------------------------------------------------------------------------
21// `-x` condition type constants (c:76-89).
22// ---------------------------------------------------------------------------
23/// `CCT_UNUSED` constant.
24pub const CCT_UNUSED: i32 = 0; // c:76
25/// `CCT_POS` constant.
26pub const CCT_POS: i32 = 1; // c:77
27/// `CCT_CURSTR` constant.
28pub const CCT_CURSTR: i32 = 2; // c:78
29/// `CCT_CURPAT` constant.
30pub const CCT_CURPAT: i32 = 3; // c:79
31/// `CCT_WORDSTR` constant.
32pub const CCT_WORDSTR: i32 = 4; // c:80
33/// `CCT_WORDPAT` constant.
34pub const CCT_WORDPAT: i32 = 5; // c:81
35/// `CCT_CURSUF` constant.
36pub const CCT_CURSUF: i32 = 6; // c:82
37/// `CCT_CURPRE` constant.
38pub const CCT_CURPRE: i32 = 7; // c:83
39/// `CCT_CURSUB` constant.
40pub const CCT_CURSUB: i32 = 8; // c:84
41/// `CCT_CURSUBC` constant.
42pub const CCT_CURSUBC: i32 = 9; // c:85
43/// `CCT_NUMWORDS` constant.
44pub const CCT_NUMWORDS: i32 = 10; // c:86
45/// `CCT_RANGESTR` constant.
46pub const CCT_RANGESTR: i32 = 11; // c:87
47/// `CCT_RANGEPAT` constant.
48pub const CCT_RANGEPAT: i32 = 12; // c:88
49/// `CCT_QUOTE` constant.
50pub const CCT_QUOTE: i32 = 13; // c:89
51
52// ---------------------------------------------------------------------------
53// Primary completion-target flags (`mask`, c:118-149).
54// Each bit selects one completion-source kind (files, vars, jobs, ...)
55// the compctl spec expands.
56// ---------------------------------------------------------------------------
57/// `CC_FILES` constant.
58pub const CC_FILES: u64 = 1 << 0; // c:118
59/// `CC_COMMPATH` constant.
60pub const CC_COMMPATH: u64 = 1 << 1; // c:119
61/// `CC_REMOVE` constant.
62pub const CC_REMOVE: u64 = 1 << 2; // c:120
63/// `CC_OPTIONS` constant.
64pub const CC_OPTIONS: u64 = 1 << 3; // c:121
65/// `CC_VARS` constant.
66pub const CC_VARS: u64 = 1 << 4; // c:122
67/// `CC_BINDINGS` constant.
68pub const CC_BINDINGS: u64 = 1 << 5; // c:123
69/// `CC_ARRAYS` constant.
70pub const CC_ARRAYS: u64 = 1 << 6; // c:124
71/// `CC_INTVARS` constant.
72pub const CC_INTVARS: u64 = 1 << 7; // c:125
73/// `CC_SHFUNCS` constant.
74pub const CC_SHFUNCS: u64 = 1 << 8; // c:126
75/// `CC_PARAMS` constant.
76pub const CC_PARAMS: u64 = 1 << 9; // c:127
77/// `CC_ENVVARS` constant.
78pub const CC_ENVVARS: u64 = 1 << 10; // c:128
79/// `CC_JOBS` constant.
80pub const CC_JOBS: u64 = 1 << 11; // c:129
81/// `CC_RUNNING` constant.
82pub const CC_RUNNING: u64 = 1 << 12; // c:130
83/// `CC_STOPPED` constant.
84pub const CC_STOPPED: u64 = 1 << 13; // c:131
85/// `CC_BUILTINS` constant.
86pub const CC_BUILTINS: u64 = 1 << 14; // c:132
87/// `CC_ALREG` constant.
88pub const CC_ALREG: u64 = 1 << 15; // c:133
89/// `CC_ALGLOB` constant.
90pub const CC_ALGLOB: u64 = 1 << 16; // c:134
91/// `CC_USERS` constant.
92pub const CC_USERS: u64 = 1 << 17; // c:135
93/// `CC_DISCMDS` constant.
94pub const CC_DISCMDS: u64 = 1 << 18; // c:136
95/// `CC_EXCMDS` constant.
96pub const CC_EXCMDS: u64 = 1 << 19; // c:137
97/// `CC_SCALARS` constant.
98pub const CC_SCALARS: u64 = 1 << 20; // c:138
99/// `CC_READONLYS` constant.
100pub const CC_READONLYS: u64 = 1 << 21; // c:139
101/// `CC_SPECIALS` constant.
102pub const CC_SPECIALS: u64 = 1 << 22; // c:140
103/// `CC_DELETE` constant.
104pub const CC_DELETE: u64 = 1 << 23; // c:141
105/// `CC_NAMED` constant.
106pub const CC_NAMED: u64 = 1 << 24; // c:142
107/// `CC_QUOTEFLAG` constant.
108pub const CC_QUOTEFLAG: u64 = 1 << 25; // c:143
109/// `CC_EXTCMDS` constant.
110pub const CC_EXTCMDS: u64 = 1 << 26; // c:144
111/// `CC_RESWDS` constant.
112pub const CC_RESWDS: u64 = 1 << 27; // c:145
113/// `CC_DIRS` constant.
114pub const CC_DIRS: u64 = 1 << 28; // c:146
115/// `CC_EXPANDEXPL` constant.
116pub const CC_EXPANDEXPL: u64 = 1 << 30; // c:148
117/// `CC_RESERVED` constant.
118pub const CC_RESERVED: u64 = 1 << 31; // c:149
119
120// ---------------------------------------------------------------------------
121// Secondary completion-target flags (`mask2`, c:152-158).
122// ---------------------------------------------------------------------------
123/// `CC_NOSORT` constant.
124pub const CC_NOSORT: u64 = 1 << 0; // c:152
125/// `CC_XORCONT` constant.
126pub const CC_XORCONT: u64 = 1 << 1; // c:153
127/// `CC_CCCONT` constant.
128pub const CC_CCCONT: u64 = 1 << 2; // c:154
129/// `CC_PATCONT` constant.
130pub const CC_PATCONT: u64 = 1 << 3; // c:155
131/// `CC_DEFCONT` constant.
132pub const CC_DEFCONT: u64 = 1 << 4; // c:156
133/// `CC_UNIQCON` constant.
134pub const CC_UNIQCON: u64 = 1 << 5; // c:157
135/// `CC_UNIQALL` constant.
136pub const CC_UNIQALL: u64 = 1 << 6; // c:158
137
138// ---------------------------------------------------------------------------
139// Typedef structs (c:32-115).
140//
141// C uses linked lists threaded through `next` pointers. The Rust
142// port substitutes `Option<Box<...>>` for the same self-referential
143// chain; the linked-list semantics are preserved.
144// ---------------------------------------------------------------------------
145
146/// Port of `struct compctlp` from `Src/Zle/compctl.h:39-42`. Hash
147/// table node entry holding a pointer to the compctl descriptor.
148///
149/// C definition (c:39-42):
150/// ```c
151/// struct compctlp {
152///     struct hashnode node;
153///     Compctl cc;
154/// };
155/// ```
156///
157/// The Rust port omits the `hashnode` head (zshrs's hashtable
158/// machinery threads name+next through a separate scaffold) and
159/// keeps the semantic payload — a pointer to the compctl descriptor.
160#[derive(Debug, Clone)]
161#[allow(non_camel_case_types)]
162pub struct Compctlp {
163    // c:39
164    pub cc: std::sync::Arc<Compctl>, // c:41
165}
166
167/// Port of `struct patcomp` from `Src/Zle/compctl.h:46-50`. Linked-
168/// list node for the pattern-compctl registry (entries created by
169/// `compctl -p PATTERN ...`).
170///
171/// C definition (c:46-50):
172/// ```c
173/// struct patcomp {
174///     Patcomp next;
175///     char *pat;
176///     Compctl cc;
177/// };
178/// ```
179#[derive(Debug, Clone)]
180#[allow(non_camel_case_types)]
181pub struct Patcomp {
182    // c:46
183    pub next: Option<Box<Patcomp>>,  // c:47
184    pub pat: String,                 // c:48
185    pub cc: std::sync::Arc<Compctl>, // c:49
186}
187
188/// Port of `struct compcond` from `Src/Zle/compctl.h:54-74`. The
189/// per-condition descriptor for `compctl -x`.
190///
191/// C definition (c:54-74):
192/// ```c
193/// struct compcond {
194///     Compcond and, or;
195///     int type;            /* one of CCT_* */
196///     int n;               /* array length */
197///     union {
198///         struct { int *a, *b; } r;       /* CCT_POS, CCT_NUMWORDS */
199///         struct { int *p; char **s; } s;  /* CCT_CURSTR, CCT_CURPAT, ... */
200///         struct { char **a, **b; } l;     /* CCT_RANGESTR, ... */
201///     } u;
202/// };
203/// ```
204///
205/// The Rust port collapses C's `union` into an explicit enum
206/// (`CompcondData`) since Rust unions require unsafe; the dispatch
207/// is by `typ` per the C convention.
208#[derive(Debug, Clone, Default)]
209#[allow(non_camel_case_types)]
210pub struct Compcond {
211    // c:54
212    pub and: Option<Box<Compcond>>, // c:55
213    pub or: Option<Box<Compcond>>,  // c:55
214    pub typ: i32,                   // c:56  (Rust keyword `type`)
215    pub n: i32,                     // c:57
216    pub u: CompcondData,            // c:58 union
217}
218
219/// Port of the anonymous `union { struct r,s,l }` inside `compcond`
220/// at `Src/Zle/compctl.h:58-73`. The C union is dispatched by
221/// `typ` (one of the `CCT_*` constants).
222#[derive(Debug, Clone, Default)]
223#[allow(non_camel_case_types)]
224pub enum CompcondData {
225    // c:58
226    /// Port of `struct { int *a, *b; } r` (c:59-62) — used by
227    /// `CCT_POS`, `CCT_NUMWORDS`.
228    R { a: Vec<i32>, b: Vec<i32> },
229    /// Port of `struct { int *p; char **s; } s` (c:63-66) — used by
230    /// `CCT_CURSTR`, `CCT_CURPAT`, `CCT_CURSUF`, `CCT_CURPRE`,
231    /// `CCT_CURSUB`, `CCT_CURSUBC`, `CCT_WORDSTR`, `CCT_WORDPAT`,
232    /// `CCT_QUOTE`.
233    S { p: Vec<i32>, s: Vec<String> },
234    /// Port of `struct { char **a, **b; } l` (c:68-71) — used by
235    /// `CCT_RANGESTR`, `CCT_RANGEPAT`.
236    L { a: Vec<String>, b: Vec<String> },
237    /// Empty (CCT_UNUSED).
238    #[default]
239    Unused,
240}
241
242/// Port of `struct compctl` from `Src/Zle/compctl.h:93-115`. The
243/// real per-command compctl descriptor — what `compctl name args`
244/// allocates and registers in the `compctltab` hashtable.
245///
246/// C definition (c:93-115) — 22 fields. Field names + types
247/// preserved verbatim; pointer types collapse to `Option<String>` /
248/// `Option<std::sync::Arc<Compctl>>` etc. as appropriate.
249#[derive(Debug, Clone, Default)]
250#[allow(non_camel_case_types)]
251pub struct Compctl {
252    // c:93
253    /// Reference count.
254    pub refc: i32, // c:94
255    /// Next compctl in a `-x` chain.
256    pub next: Option<std::sync::Arc<Compctl>>, // c:95
257    /// Mask of completion-target flags (`CC_*`).
258    pub mask: u64, // c:96
259    /// Secondary mask of completion-target flags (`CC_*`, mask2).
260    pub mask2: u64, // c:96
261    /// `-k` variable name.
262    pub keyvar: Option<String>, // c:97
263    /// `-g` glob pattern.
264    pub glob: Option<String>, // c:98
265    /// `-s` expansion string.
266    pub str: Option<String>, // c:99 (Rust keyword `str`)
267    /// `-K` function name.
268    pub func: Option<String>, // c:100
269    /// `-X` explanation.
270    pub explain: Option<String>, // c:101
271    /// `-y` user-defined description for listing.
272    pub ylist: Option<String>, // c:102
273    /// `-P` prefix.
274    pub prefix: Option<String>, // c:103
275    /// `-S` suffix.
276    pub suffix: Option<String>, // c:103
277    /// `-l` command name to use.
278    pub subcmd: Option<String>, // c:104
279    /// `-1` command name to use.
280    pub substr: Option<String>, // c:105
281    /// `-w` with-directory.
282    pub withd: Option<String>, // c:106
283    /// `-H` history pattern.
284    pub hpat: Option<String>, // c:107
285    /// `-H` number of events to search.
286    pub hnum: i32, // c:108
287    /// `-J`/`-V` group name.
288    pub gname: Option<String>, // c:109
289    /// `-x` first compctl in the chain.
290    pub ext: Option<std::sync::Arc<Compctl>>, // c:110
291    /// `-x` condition for this compctl.
292    pub cond: Option<Box<Compcond>>, // c:111
293    /// `+` xor'ed compctl chain.
294    pub xor: Option<std::sync::Arc<Compctl>>, // c:112
295    /// `-M` matcher control — head of the Cmatcher chain compiled
296    /// from this compctl's match-spec arg.
297    pub matcher: Option<Box<crate::ported::zle::comp_h::Cmatcher>>, // c:113
298    /// `-M` matcher string.
299    pub mstr: Option<String>, // c:114
300}
301
302#[cfg(test)]
303mod tests {
304    use super::*;
305    use crate::ported::zle::zle_main::zle_test_setup;
306
307    /// Verifies CCT_* values per c:76-89.
308    #[test]
309    fn cct_constants_correct() {
310        let _g = crate::test_util::global_state_lock();
311        let _g = zle_test_setup();
312        assert_eq!(CCT_UNUSED, 0);
313        assert_eq!(CCT_POS, 1);
314        assert_eq!(CCT_CURSTR, 2);
315        assert_eq!(CCT_QUOTE, 13);
316    }
317
318    /// Verifies CC_* primary mask values per c:118-149 — single-bit,
319    /// non-overlapping.
320    #[test]
321    fn cc_primary_mask_bits_distinct() {
322        let _g = crate::test_util::global_state_lock();
323        let _g = zle_test_setup();
324        let all = CC_FILES
325            | CC_COMMPATH
326            | CC_REMOVE
327            | CC_OPTIONS
328            | CC_VARS
329            | CC_BINDINGS
330            | CC_ARRAYS
331            | CC_INTVARS
332            | CC_SHFUNCS
333            | CC_PARAMS
334            | CC_ENVVARS
335            | CC_JOBS
336            | CC_RUNNING
337            | CC_STOPPED
338            | CC_BUILTINS
339            | CC_ALREG
340            | CC_ALGLOB
341            | CC_USERS
342            | CC_DISCMDS
343            | CC_EXCMDS
344            | CC_SCALARS
345            | CC_READONLYS
346            | CC_SPECIALS
347            | CC_DELETE
348            | CC_NAMED
349            | CC_QUOTEFLAG
350            | CC_EXTCMDS
351            | CC_RESWDS
352            | CC_DIRS
353            | CC_EXPANDEXPL
354            | CC_RESERVED;
355        assert_eq!(all.count_ones(), 31); // 30 sequential + 30 + 31 (skips bit 29)
356    }
357
358    /// Verifies the secondary mask values per c:152-158.
359    #[test]
360    fn cc_secondary_mask_values() {
361        let _g = crate::test_util::global_state_lock();
362        let _g = zle_test_setup();
363        assert_eq!(CC_NOSORT, 1);
364        assert_eq!(CC_XORCONT, 2);
365        assert_eq!(CC_UNIQALL, 1 << 6);
366    }
367
368    /// Verifies Compctl Default initialiser zeroes every field per
369    /// the C convention of `(Compctl) calloc(1, sizeof(...))`.
370    #[test]
371    fn compctl_default_zeros_fields() {
372        let _g = crate::test_util::global_state_lock();
373        let _g = zle_test_setup();
374        let cc = Compctl::default();
375        assert_eq!(cc.refc, 0);
376        assert!(cc.next.is_none());
377        assert_eq!(cc.mask, 0);
378        assert_eq!(cc.mask2, 0);
379        assert!(cc.keyvar.is_none());
380        assert!(cc.cond.is_none());
381        assert!(cc.xor.is_none());
382        assert_eq!(cc.hnum, 0);
383    }
384
385    /// Verifies Compcond Default starts in CCT_UNUSED state.
386    #[test]
387    fn compcond_default_is_unused() {
388        let _g = crate::test_util::global_state_lock();
389        let _g = zle_test_setup();
390        let c = Compcond::default();
391        assert_eq!(c.typ, CCT_UNUSED);
392        assert!(matches!(c.u, CompcondData::Unused));
393    }
394
395    /// Verifies the CompcondData variants align with the C union
396    /// dispatch per c:58-73.
397    #[test]
398    fn compcond_data_variants() {
399        let _g = crate::test_util::global_state_lock();
400        let _g = zle_test_setup();
401        let r = CompcondData::R {
402            a: vec![0, 1],
403            b: vec![2, 3],
404        };
405        if let CompcondData::R { a, b } = r {
406            assert_eq!(a, vec![0, 1]);
407            assert_eq!(b, vec![2, 3]);
408        } else {
409            panic!("expected R variant");
410        }
411        let s = CompcondData::S {
412            p: vec![1],
413            s: vec!["x".into()],
414        };
415        assert!(matches!(s, CompcondData::S { .. }));
416        let l = CompcondData::L {
417            a: vec!["lo".into()],
418            b: vec!["hi".into()],
419        };
420        assert!(matches!(l, CompcondData::L { .. }));
421    }
422
423    /// c:76-89 — Every CCT_* constant is a unique non-negative
424    /// integer. Pin uniqueness so a copy-paste regen doesn't double
425    /// up a tag (which would silently route two different
426    /// completion-condition kinds through the same dispatch arm).
427    #[test]
428    fn cct_constants_are_unique() {
429        let _g = crate::test_util::global_state_lock();
430        let _g = zle_test_setup();
431        let all = [
432            CCT_UNUSED,
433            CCT_POS,
434            CCT_CURSTR,
435            CCT_CURPAT,
436            CCT_WORDSTR,
437            CCT_WORDPAT,
438            CCT_CURSUF,
439            CCT_CURPRE,
440            CCT_CURSUB,
441            CCT_CURSUBC,
442            CCT_NUMWORDS,
443            CCT_RANGESTR,
444            CCT_RANGEPAT,
445            CCT_QUOTE,
446        ];
447        let unique: std::collections::HashSet<_> = all.iter().copied().collect();
448        assert_eq!(unique.len(), all.len(), "duplicate CCT_* constant detected");
449        for &v in &all {
450            assert!(v >= 0, "CCT_* constants must be non-negative");
451        }
452    }
453
454    /// c:76 — CCT_UNUSED MUST be 0. The C source uses zero-init as
455    /// the implicit "no condition" sentinel; a regression that sets
456    /// CCT_UNUSED = 1 would mark every just-allocated condition as
457    /// CCT_POS by accident.
458    #[test]
459    fn cct_unused_is_zero() {
460        let _g = crate::test_util::global_state_lock();
461        assert_eq!(CCT_UNUSED, 0, "CCT_UNUSED must be the zero-init sentinel");
462    }
463
464    /// c:118-127 — CC_* primary-mask bits are distinct singletons.
465    /// Pin the bit-packing because the c:152 "primary mask" vs
466    /// c:154-158 "secondary mask" distinction relies on the primary
467    /// bits all being non-overlapping.
468    #[test]
469    fn cc_primary_mask_bits_are_distinct_singletons() {
470        let _g = crate::test_util::global_state_lock();
471        let primary = [
472            CC_FILES,
473            CC_COMMPATH,
474            CC_REMOVE,
475            CC_OPTIONS,
476            CC_VARS,
477            CC_BINDINGS,
478            CC_ARRAYS,
479            CC_INTVARS,
480            CC_SHFUNCS,
481            CC_PARAMS,
482            CC_ENVVARS,
483        ];
484        for &m in &primary {
485            assert_eq!(
486                m.count_ones(),
487                1,
488                "primary CC_ mask {} has {} bits set",
489                m,
490                m.count_ones()
491            );
492        }
493        let mut all: u64 = 0;
494        for &m in &primary {
495            assert_eq!(all & m, 0, "primary CC_ mask {} overlaps", m);
496            all |= m;
497        }
498    }
499
500    /// c:108 — `Compctl::default()` Default impl produces an empty
501    /// struct ready for population. After a default + manual field
502    /// write, the other fields must remain at their zero-init values.
503    #[test]
504    fn compctl_default_partial_population_doesnt_clobber_other_fields() {
505        let _g = crate::test_util::global_state_lock();
506        let _g = zle_test_setup();
507        let mut cc = Compctl::default();
508        cc.mask = CC_FILES;
509        assert_eq!(cc.mask, CC_FILES);
510        // Every OTHER field must still be at default
511        assert_eq!(cc.refc, 0);
512        assert!(cc.next.is_none());
513        assert_eq!(cc.mask2, 0);
514        assert!(cc.keyvar.is_none());
515        assert!(cc.cond.is_none());
516        assert_eq!(cc.hnum, 0);
517    }
518
519    /// `Compcond::default()` produces a CCT_UNUSED node with the
520    /// `Unused` data variant. Pin the simultaneous shape so a
521    /// regression that picks one but not the other (e.g. CCT_POS
522    /// with Unused data) gets caught.
523    #[test]
524    fn compcond_default_typ_and_data_are_consistent() {
525        let _g = crate::test_util::global_state_lock();
526        let _g = zle_test_setup();
527        let c = Compcond::default();
528        assert_eq!(c.typ, CCT_UNUSED, "tag must be UNUSED");
529        assert!(
530            matches!(c.u, CompcondData::Unused),
531            "data must be CompcondData::Unused"
532        );
533    }
534
535    /// c:118-149 — Full sweep of CC_* primary-mask bits 0..31. Each
536    /// must occupy a distinct bit position. Catches a regen that
537    /// renumbers two flags to the same shift.
538    #[test]
539    fn cc_primary_mask_full_sweep_no_overlap() {
540        let _g = crate::test_util::global_state_lock();
541        let primary = [
542            CC_FILES,
543            CC_COMMPATH,
544            CC_REMOVE,
545            CC_OPTIONS,
546            CC_VARS,
547            CC_BINDINGS,
548            CC_ARRAYS,
549            CC_INTVARS,
550            CC_SHFUNCS,
551            CC_PARAMS,
552            CC_ENVVARS,
553            CC_STOPPED,
554            CC_BUILTINS,
555            CC_ALREG,
556            CC_ALGLOB,
557            CC_USERS,
558            CC_DISCMDS,
559            CC_EXCMDS,
560            CC_SCALARS,
561            CC_READONLYS,
562            CC_SPECIALS,
563            CC_DELETE,
564            CC_NAMED,
565            CC_QUOTEFLAG,
566            CC_EXTCMDS,
567            CC_RESWDS,
568            CC_DIRS,
569            CC_EXPANDEXPL,
570            CC_RESERVED,
571        ];
572        for &m in &primary {
573            assert_eq!(
574                m.count_ones(),
575                1,
576                "primary CC_ mask {:#x} must be single bit",
577                m
578            );
579        }
580        let mut all: u64 = 0;
581        for &m in &primary {
582            assert_eq!(all & m, 0, "CC_ mask {:#x} overlaps with previous flags", m);
583            all |= m;
584        }
585    }
586
587    /// c:148 — CC_EXPANDEXPL lives at bit 30 (NOT 29). Pin the
588    /// gap-at-bit-29 because the C source documents the bit-29
589    /// hole at c:147. A regen that "fills the gap" would shift
590    /// every subsequent flag.
591    #[test]
592    fn cc_expandexpl_at_bit_30_skips_bit_29() {
593        let _g = crate::test_util::global_state_lock();
594        assert_eq!(
595            CC_EXPANDEXPL,
596            1 << 30,
597            "c:148 — CC_EXPANDEXPL must be at bit 30 (bit 29 is the gap)"
598        );
599        // Verify nothing else IS bit 29
600        let all_primary = [
601            CC_FILES,
602            CC_COMMPATH,
603            CC_REMOVE,
604            CC_OPTIONS,
605            CC_VARS,
606            CC_BINDINGS,
607            CC_ARRAYS,
608            CC_INTVARS,
609            CC_SHFUNCS,
610            CC_PARAMS,
611            CC_ENVVARS,
612            CC_STOPPED,
613            CC_BUILTINS,
614            CC_ALREG,
615            CC_ALGLOB,
616            CC_USERS,
617            CC_DISCMDS,
618            CC_EXCMDS,
619            CC_SCALARS,
620            CC_READONLYS,
621            CC_SPECIALS,
622            CC_DELETE,
623            CC_NAMED,
624            CC_QUOTEFLAG,
625            CC_EXTCMDS,
626            CC_RESWDS,
627            CC_DIRS,
628            CC_EXPANDEXPL,
629            CC_RESERVED,
630        ];
631        let bit_29: u64 = 1 << 29;
632        for &m in &all_primary {
633            assert_ne!(
634                m, bit_29,
635                "no primary mask should occupy bit 29 (the documented gap)"
636            );
637        }
638    }
639
640    /// c:149 — CC_RESERVED is bit 31 (the high bit). Pin the
641    /// boundary so a regen that extends into bit 32 (u64 vs i32
642    /// confusion) gets caught.
643    #[test]
644    fn cc_reserved_is_bit_31() {
645        let _g = crate::test_util::global_state_lock();
646        assert_eq!(CC_RESERVED, 1u64 << 31);
647    }
648
649    /// c:152-158 — Secondary-mask (mask2) flags occupy bits 0-6 of
650    /// their OWN namespace. They DELIBERATELY collide with primary
651    /// mask values (CC_NOSORT = 1 = CC_FILES) — the dispatcher
652    /// routes via the mask vs mask2 field.
653    #[test]
654    fn secondary_mask_collides_with_primary_by_design() {
655        let _g = crate::test_util::global_state_lock();
656        // CC_NOSORT (mask2 bit 0) and CC_FILES (mask bit 0) both = 1
657        assert_eq!(
658            CC_NOSORT, CC_FILES,
659            "collision is intentional — different mask fields"
660        );
661        // CC_XORCONT (mask2 bit 1) and CC_COMMPATH (mask bit 1) both = 2
662        assert_eq!(CC_XORCONT, CC_COMMPATH);
663        // ... but mask2 has its own no-overlap structure
664        let secondary = [
665            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
666        ];
667        let mut all: u64 = 0;
668        for &m in &secondary {
669            assert_eq!(
670                m.count_ones(),
671                1,
672                "secondary CC_ mask {:#x} must be single bit",
673                m
674            );
675            assert_eq!(
676                all & m,
677                0,
678                "secondary {:#x} overlaps within mask2 namespace",
679                m
680            );
681            all |= m;
682        }
683    }
684
685    /// c:76-89 — CCT_* values are sequential (0..13). Pin the
686    /// dense layout so a regen that introduces a gap silently
687    /// breaks the dispatcher's `(type - CCT_POS)` subtraction.
688    #[test]
689    fn cct_values_are_sequential_zero_through_thirteen() {
690        let _g = crate::test_util::global_state_lock();
691        let in_order = [
692            CCT_UNUSED,
693            CCT_POS,
694            CCT_CURSTR,
695            CCT_CURPAT,
696            CCT_WORDSTR,
697            CCT_WORDPAT,
698            CCT_CURSUF,
699            CCT_CURPRE,
700            CCT_CURSUB,
701            CCT_CURSUBC,
702            CCT_NUMWORDS,
703            CCT_RANGESTR,
704            CCT_RANGEPAT,
705            CCT_QUOTE,
706        ];
707        for (i, &v) in in_order.iter().enumerate() {
708            assert_eq!(
709                v, i as i32,
710                "CCT_ at position {} must be {}, got {}",
711                i, i, v
712            );
713        }
714    }
715
716    // ═══════════════════════════════════════════════════════════════════
717    // Additional C-parity tests for Src/Zle/compctl.h constants.
718    // ═══════════════════════════════════════════════════════════════════
719
720    /// c:76-89 — CCT_* values are sequential 0..14 (no holes).
721    #[test]
722    fn cct_values_pairwise_distinct() {
723        let all = [
724            CCT_UNUSED,
725            CCT_POS,
726            CCT_CURSTR,
727            CCT_CURPAT,
728            CCT_WORDSTR,
729            CCT_WORDPAT,
730            CCT_CURSUF,
731            CCT_CURPRE,
732            CCT_CURSUB,
733            CCT_CURSUBC,
734            CCT_NUMWORDS,
735            CCT_RANGESTR,
736            CCT_RANGEPAT,
737            CCT_QUOTE,
738        ];
739        let unique: std::collections::HashSet<_> = all.iter().copied().collect();
740        assert_eq!(unique.len(), all.len(), "CCT_* must be pairwise distinct");
741    }
742
743    /// c:76-89 — CCT_* canonical mid-table values (spot-check).
744    #[test]
745    fn cct_canonical_mid_values() {
746        assert_eq!(CCT_WORDSTR, 4);
747        assert_eq!(CCT_WORDPAT, 5);
748        assert_eq!(CCT_CURSUF, 6);
749        assert_eq!(CCT_CURPRE, 7);
750        assert_eq!(CCT_NUMWORDS, 10);
751        assert_eq!(CCT_RANGESTR, 11);
752        assert_eq!(CCT_RANGEPAT, 12);
753    }
754
755    /// c:118 — CC_FILES is bit 0 (the most common file-completion flag,
756    /// hot-path bit). Pin so a regen flipping bit assignments doesn't
757    /// silently break Tab completion of filenames.
758    #[test]
759    fn cc_files_is_bit_zero() {
760        assert_eq!(CC_FILES, 1);
761    }
762
763    /// c:118-128 — first 10 CC_* mask bits are pairwise disjoint
764    /// single-bit values.
765    #[test]
766    fn cc_first_10_flags_are_pairwise_disjoint_single_bits() {
767        let flags = [
768            CC_FILES,
769            CC_COMMPATH,
770            CC_REMOVE,
771            CC_OPTIONS,
772            CC_VARS,
773            CC_BINDINGS,
774            CC_ARRAYS,
775            CC_INTVARS,
776            CC_SHFUNCS,
777            CC_PARAMS,
778        ];
779        for (i, &a) in flags.iter().enumerate() {
780            assert!(a.is_power_of_two(), "CC_* flag {} must be single bit", a);
781            for &b in flags.iter().skip(i + 1) {
782                assert_eq!(a & b, 0, "{} and {} overlap", a, b);
783            }
784        }
785    }
786
787    /// c:118-128 — first 10 CC_* mask bits in canonical 1<<N positions.
788    #[test]
789    fn cc_first_10_flags_canonical_positions() {
790        assert_eq!(CC_FILES, 1 << 0);
791        assert_eq!(CC_COMMPATH, 1 << 1);
792        assert_eq!(CC_REMOVE, 1 << 2);
793        assert_eq!(CC_OPTIONS, 1 << 3);
794        assert_eq!(CC_VARS, 1 << 4);
795        assert_eq!(CC_BINDINGS, 1 << 5);
796        assert_eq!(CC_ARRAYS, 1 << 6);
797        assert_eq!(CC_INTVARS, 1 << 7);
798        assert_eq!(CC_SHFUNCS, 1 << 8);
799        assert_eq!(CC_PARAMS, 1 << 9);
800    }
801
802    /// c:152-158 — CC_NOSORT/XORCONT canonical positions in secondary
803    /// mask namespace (separate u64 from CC_FILES etc.).
804    #[test]
805    fn cc_secondary_low_bits_canonical() {
806        assert_eq!(CC_NOSORT, 1);
807        assert_eq!(CC_XORCONT, 2);
808    }
809
810    /// c:155 — CC_UNIQALL = 1 << 6.
811    #[test]
812    fn cc_uniqall_is_bit_6_in_secondary() {
813        assert_eq!(CC_UNIQALL, 1 << 6);
814    }
815
816    // ═══════════════════════════════════════════════════════════════════
817    // Additional C-parity tests for Src/Zle/compctl.h c:131-156 CC_*
818    // ═══════════════════════════════════════════════════════════════════
819
820    /// c:131-149 — every primary CC_* flag value is a power of two.
821    #[test]
822    fn cc_primary_flags_all_powers_of_two_full_sweep() {
823        for &v in &[
824            CC_STOPPED,
825            CC_BUILTINS,
826            CC_ALREG,
827            CC_ALGLOB,
828            CC_USERS,
829            CC_DISCMDS,
830            CC_EXCMDS,
831            CC_SCALARS,
832            CC_READONLYS,
833            CC_SPECIALS,
834            CC_DELETE,
835            CC_NAMED,
836            CC_QUOTEFLAG,
837            CC_EXTCMDS,
838            CC_RESWDS,
839            CC_DIRS,
840            CC_EXPANDEXPL,
841            CC_RESERVED,
842        ] {
843            assert!(
844                v.is_power_of_two(),
845                "CC_* primary {:#x} must be single bit",
846                v
847            );
848        }
849    }
850
851    /// c:148 — CC_EXPANDEXPL = bit 30 (skips bit 29 by design).
852    #[test]
853    fn cc_expandexpl_skips_bit_29() {
854        assert_eq!(CC_EXPANDEXPL, 1u64 << 30, "c:148 = bit 30");
855        // Bit 29 is reserved (intentionally unused per C source).
856    }
857
858    /// c:152-158 — secondary CC_* flags are powers of two.
859    #[test]
860    fn cc_secondary_flags_all_powers_of_two() {
861        for &v in &[
862            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
863        ] {
864            assert!(
865                v.is_power_of_two(),
866                "CC_* secondary {:#x} must be single bit",
867                v
868            );
869        }
870    }
871
872    /// c:152-158 — secondary CC_* are pairwise distinct.
873    #[test]
874    fn cc_secondary_flags_pairwise_distinct() {
875        let codes = [
876            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
877        ];
878        let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
879        assert_eq!(unique.len(), codes.len(), "CC_* secondary must be distinct");
880    }
881
882    /// c:131-149 — primary CC_* canonical bit positions match c:113-149.
883    #[test]
884    fn cc_primary_canonical_high_bit_positions() {
885        assert_eq!(CC_DIRS, 1u64 << 28, "c:146");
886        assert_eq!(CC_RESERVED, 1u64 << 31, "c:149");
887        assert_eq!(CC_DELETE, 1u64 << 23, "c:141");
888        assert_eq!(CC_NAMED, 1u64 << 24, "c:142");
889        assert_eq!(CC_USERS, 1u64 << 17, "c:135");
890    }
891
892    /// c:131-149 + c:152-158 — every CC_* fits in u64 (compile-time
893    /// type pin).
894    #[test]
895    fn cc_all_flags_are_u64_type() {
896        let _: u64 = CC_STOPPED;
897        let _: u64 = CC_NOSORT;
898        let _: u64 = CC_RESERVED;
899    }
900
901    /// c:152-158 — CC_NOSORT through CC_UNIQALL form contiguous low-7 bits.
902    #[test]
903    fn cc_secondary_form_contiguous_low_bits() {
904        let mut bits: Vec<u64> = vec![
905            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
906        ];
907        bits.sort();
908        for (i, &b) in bits.iter().enumerate() {
909            assert_eq!(b, 1u64 << i, "secondary bit {} must be 1<<{}", i, i);
910        }
911    }
912
913    /// c:131-149 — primary CC_* form mostly contiguous from bit 0 up
914    /// (with bit 29 reserved gap to bit 30 EXPANDEXPL).
915    #[test]
916    fn cc_primary_no_gaps_through_bit_28() {
917        // Bits 0..28 must all be claimed by primary CC_* flags.
918        let all = [
919            CC_FILES,
920            CC_COMMPATH,
921            CC_REMOVE,
922            CC_OPTIONS,
923            CC_VARS,
924            CC_BINDINGS,
925            CC_ARRAYS,
926            CC_INTVARS,
927            CC_SHFUNCS,
928            CC_PARAMS,
929            CC_ENVVARS,
930            CC_JOBS,
931            CC_RUNNING,
932            CC_STOPPED,
933            CC_BUILTINS,
934            CC_ALREG,
935            CC_ALGLOB,
936            CC_USERS,
937            CC_DISCMDS,
938            CC_EXCMDS,
939            CC_SCALARS,
940            CC_READONLYS,
941            CC_SPECIALS,
942            CC_DELETE,
943            CC_NAMED,
944            CC_QUOTEFLAG,
945            CC_EXTCMDS,
946            CC_RESWDS,
947            CC_DIRS,
948        ];
949        let or_all: u64 = all.iter().fold(0, |acc, &v| acc | v);
950        assert_eq!(or_all, (1u64 << 29) - 1, "bits 0..28 must all be set");
951    }
952
953    // ═══════════════════════════════════════════════════════════════════
954    // Additional C-parity tests for Src/Zle/compctl.h
955    // c:76-89 CCT_* / c:118-149 primary CC_* / c:152-158 secondary CC_*
956    // ═══════════════════════════════════════════════════════════════════
957
958    /// c:76 — `CCT_UNUSED` is the zero sentinel (slot 0).
959    #[test]
960    fn cct_unused_is_zero_sentinel() {
961        assert_eq!(CCT_UNUSED, 0, "c:76 — UNUSED is the slot-0 sentinel");
962    }
963
964    /// c:76-89 — all CCT_* codes are i32 (compile-time type pin).
965    #[test]
966    fn cct_codes_all_i32_type() {
967        let _: i32 = CCT_UNUSED;
968        let _: i32 = CCT_POS;
969        let _: i32 = CCT_QUOTE;
970    }
971
972    /// c:76-89 — CCT_* codes cover slots 0..=13 with no gaps/dups.
973    #[test]
974    fn cct_codes_dense_0_through_13() {
975        let mut codes = vec![
976            CCT_UNUSED,
977            CCT_POS,
978            CCT_CURSTR,
979            CCT_CURPAT,
980            CCT_WORDSTR,
981            CCT_WORDPAT,
982            CCT_CURSUF,
983            CCT_CURPRE,
984            CCT_CURSUB,
985            CCT_CURSUBC,
986            CCT_NUMWORDS,
987            CCT_RANGESTR,
988            CCT_RANGEPAT,
989            CCT_QUOTE,
990        ];
991        codes.sort();
992        let expected: Vec<i32> = (0..=13).collect();
993        assert_eq!(
994            codes, expected,
995            "CCT_* must cover slots 0..=13 with no gaps/dups"
996        );
997    }
998
999    /// c:118 — `CC_FILES` is canonical bit 0 (alt name pin).
1000    #[test]
1001    fn cc_files_is_bit_zero_alt() {
1002        assert_eq!(CC_FILES, 1u64 << 0, "c:118 — FILES is bit 0");
1003    }
1004
1005    /// c:131-149 — primary CC_* form a complete bitset:
1006    /// (bits 0..28) | EXPANDEXPL(30) | RESERVED(31), with bit 29 gap.
1007    #[test]
1008    fn cc_primary_complete_bitset_with_bit29_gap() {
1009        let all = [
1010            CC_FILES,
1011            CC_COMMPATH,
1012            CC_REMOVE,
1013            CC_OPTIONS,
1014            CC_VARS,
1015            CC_BINDINGS,
1016            CC_ARRAYS,
1017            CC_INTVARS,
1018            CC_SHFUNCS,
1019            CC_PARAMS,
1020            CC_ENVVARS,
1021            CC_JOBS,
1022            CC_RUNNING,
1023            CC_STOPPED,
1024            CC_BUILTINS,
1025            CC_ALREG,
1026            CC_ALGLOB,
1027            CC_USERS,
1028            CC_DISCMDS,
1029            CC_EXCMDS,
1030            CC_SCALARS,
1031            CC_READONLYS,
1032            CC_SPECIALS,
1033            CC_DELETE,
1034            CC_NAMED,
1035            CC_QUOTEFLAG,
1036            CC_EXTCMDS,
1037            CC_RESWDS,
1038            CC_DIRS,
1039            CC_EXPANDEXPL,
1040            CC_RESERVED,
1041        ];
1042        let or_all: u64 = all.iter().fold(0, |acc, &v| acc | v);
1043        let expected = ((1u64 << 29) - 1) | (1u64 << 30) | (1u64 << 31);
1044        assert_eq!(
1045            or_all, expected,
1046            "primary CC_* must cover bits 0..28 + 30 + 31 (bit 29 reserved)"
1047        );
1048    }
1049
1050    /// c:131-149 — primary CC_* are pairwise distinct.
1051    #[test]
1052    fn cc_primary_flags_pairwise_distinct() {
1053        let codes = [
1054            CC_FILES,
1055            CC_COMMPATH,
1056            CC_REMOVE,
1057            CC_OPTIONS,
1058            CC_VARS,
1059            CC_BINDINGS,
1060            CC_ARRAYS,
1061            CC_INTVARS,
1062            CC_SHFUNCS,
1063            CC_PARAMS,
1064            CC_ENVVARS,
1065            CC_JOBS,
1066            CC_RUNNING,
1067            CC_STOPPED,
1068            CC_BUILTINS,
1069            CC_ALREG,
1070            CC_ALGLOB,
1071            CC_USERS,
1072            CC_DISCMDS,
1073            CC_EXCMDS,
1074            CC_SCALARS,
1075            CC_READONLYS,
1076            CC_SPECIALS,
1077            CC_DELETE,
1078            CC_NAMED,
1079            CC_QUOTEFLAG,
1080            CC_EXTCMDS,
1081            CC_RESWDS,
1082            CC_DIRS,
1083            CC_EXPANDEXPL,
1084            CC_RESERVED,
1085        ];
1086        let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
1087        assert_eq!(
1088            unique.len(),
1089            codes.len(),
1090            "primary CC_* must be pairwise distinct"
1091        );
1092    }
1093
1094    /// c:118-149 — every primary CC_* is non-zero (no false sentinel).
1095    #[test]
1096    fn cc_primary_all_non_zero() {
1097        for &v in &[
1098            CC_FILES,
1099            CC_COMMPATH,
1100            CC_REMOVE,
1101            CC_OPTIONS,
1102            CC_DIRS,
1103            CC_EXPANDEXPL,
1104            CC_RESERVED,
1105        ] {
1106            assert!(v > 0, "CC_* primary must be > 0; got {}", v);
1107        }
1108    }
1109
1110    /// c:152-158 — every secondary CC_* is non-zero.
1111    #[test]
1112    fn cc_secondary_all_non_zero() {
1113        for &v in &[
1114            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
1115        ] {
1116            assert!(v > 0, "CC_* secondary must be > 0; got {}", v);
1117        }
1118    }
1119
1120    // ═══════════════════════════════════════════════════════════════════
1121    // Additional C-parity pins for Src/Zle/compctl.h
1122    // c:76-89 CCT_* / c:118-149 CC_* / c:152-158 secondary CC_*
1123    // ═══════════════════════════════════════════════════════════════════
1124
1125    /// c:76-89 — every CCT_* is in 0..=13 (no out-of-range).
1126    #[test]
1127    fn cct_all_in_range_0_to_13() {
1128        for &v in &[
1129            CCT_UNUSED,
1130            CCT_POS,
1131            CCT_CURSTR,
1132            CCT_CURPAT,
1133            CCT_WORDSTR,
1134            CCT_WORDPAT,
1135            CCT_CURSUF,
1136            CCT_CURPRE,
1137            CCT_CURSUB,
1138            CCT_CURSUBC,
1139            CCT_NUMWORDS,
1140            CCT_RANGESTR,
1141            CCT_RANGEPAT,
1142            CCT_QUOTE,
1143        ] {
1144            assert!((0..=13).contains(&v), "CCT_* must be 0..=13, got {}", v);
1145        }
1146    }
1147
1148    /// c:76-89 — CCT_* values are pairwise distinct (sequential).
1149    #[test]
1150    fn cct_pairwise_distinct() {
1151        let codes = [
1152            CCT_UNUSED,
1153            CCT_POS,
1154            CCT_CURSTR,
1155            CCT_CURPAT,
1156            CCT_WORDSTR,
1157            CCT_WORDPAT,
1158            CCT_CURSUF,
1159            CCT_CURPRE,
1160            CCT_CURSUB,
1161            CCT_CURSUBC,
1162            CCT_NUMWORDS,
1163            CCT_RANGESTR,
1164            CCT_RANGEPAT,
1165            CCT_QUOTE,
1166        ];
1167        let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
1168        assert_eq!(unique.len(), codes.len(), "CCT_* pairwise distinct");
1169    }
1170
1171    /// c:76 — `CCT_UNUSED` is sentinel zero (alt pin).
1172    #[test]
1173    fn cct_unused_is_zero_sentinel_alt() {
1174        assert_eq!(CCT_UNUSED, 0, "CCT_UNUSED must be 0 (sentinel)");
1175    }
1176
1177    /// c:148 — `CC_EXPANDEXPL` skips bit 29 (gap preserved from C).
1178    #[test]
1179    fn cc_expandexpl_uses_bit_30_not_29() {
1180        assert_eq!(
1181            CC_EXPANDEXPL,
1182            1u64 << 30,
1183            "CC_EXPANDEXPL must use bit 30 (bit 29 reserved)"
1184        );
1185    }
1186
1187    /// c:152-158 — every secondary CC_* is in low 7 bits (0..7).
1188    #[test]
1189    fn cc_secondary_in_low_7_bits() {
1190        for &v in &[
1191            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
1192        ] {
1193            assert!(
1194                v < (1u64 << 7),
1195                "CC_* secondary must be < (1<<7), got 0x{:x}",
1196                v
1197            );
1198        }
1199    }
1200
1201    /// c:118-149 — bit 29 is the reserved gap; no primary CC_* uses it.
1202    #[test]
1203    fn cc_primary_bit_29_is_reserved_gap() {
1204        let codes = [
1205            CC_FILES,
1206            CC_COMMPATH,
1207            CC_REMOVE,
1208            CC_OPTIONS,
1209            CC_VARS,
1210            CC_BINDINGS,
1211            CC_ARRAYS,
1212            CC_INTVARS,
1213            CC_SHFUNCS,
1214            CC_PARAMS,
1215            CC_ENVVARS,
1216            CC_JOBS,
1217            CC_RUNNING,
1218            CC_STOPPED,
1219            CC_BUILTINS,
1220            CC_ALREG,
1221            CC_ALGLOB,
1222            CC_USERS,
1223            CC_DISCMDS,
1224            CC_EXCMDS,
1225            CC_SCALARS,
1226            CC_READONLYS,
1227            CC_SPECIALS,
1228            CC_DELETE,
1229            CC_NAMED,
1230            CC_QUOTEFLAG,
1231            CC_EXTCMDS,
1232            CC_RESWDS,
1233            CC_DIRS,
1234            CC_EXPANDEXPL,
1235            CC_RESERVED,
1236        ];
1237        for c in codes {
1238            assert_ne!(
1239                c,
1240                1u64 << 29,
1241                "no primary CC_* uses bit 29 (reserved); offending: 0x{:x}",
1242                c
1243            );
1244        }
1245    }
1246
1247    /// c:152-158 — secondary CC_* pairwise distinct.
1248    #[test]
1249    fn cc_secondary_pairwise_distinct() {
1250        let codes = [
1251            CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
1252        ];
1253        let unique: std::collections::HashSet<_> = codes.iter().copied().collect();
1254        assert_eq!(
1255            unique.len(),
1256            codes.len(),
1257            "secondary CC_* pairwise distinct"
1258        );
1259    }
1260
1261    /// c:152-158 — OR of all secondary CC_* covers bits 0..6.
1262    #[test]
1263    fn cc_secondary_or_covers_low_7_bits() {
1264        let or_all =
1265            CC_NOSORT | CC_XORCONT | CC_CCCONT | CC_PATCONT | CC_DEFCONT | CC_UNIQCON | CC_UNIQALL;
1266        assert_eq!(
1267            or_all,
1268            (1u64 << 7) - 1,
1269            "secondary CC_* must cover bits 0..6"
1270        );
1271    }
1272
1273    /// c:118 — `CC_FILES` is bit 0 (smallest primary, pin alt2).
1274    #[test]
1275    fn cc_files_is_bit_zero_pin_alt2() {
1276        assert_eq!(CC_FILES, 1u64, "CC_FILES must be bit 0");
1277    }
1278
1279    /// c:152 — `CC_NOSORT` is bit 0 (smallest secondary).
1280    #[test]
1281    fn cc_nosort_is_bit_zero() {
1282        assert_eq!(CC_NOSORT, 1u64, "CC_NOSORT must be bit 0 of secondary mask");
1283    }
1284
1285    /// c:149 — `CC_RESERVED` is the highest primary (bit 31).
1286    #[test]
1287    fn cc_reserved_is_highest_bit_31() {
1288        assert_eq!(CC_RESERVED, 1u64 << 31, "CC_RESERVED must be bit 31");
1289    }
1290
1291    /// c:158 — `CC_UNIQALL` is the highest secondary (bit 6).
1292    #[test]
1293    fn cc_uniqall_is_bit_six() {
1294        assert_eq!(CC_UNIQALL, 1u64 << 6, "CC_UNIQALL must be bit 6");
1295    }
1296
1297    /// c:78 — `CCT_CURSTR` = 2 (positional value pin).
1298    #[test]
1299    fn cct_curstr_is_two() {
1300        assert_eq!(CCT_CURSTR, 2);
1301    }
1302}