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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
use std::ops::BitOr;
use crate::component::{self, Component};

#[cfg(components_64)]
pub static MAX_COMPONENTS: usize = 64;
#[cfg(components_128)]
pub static MAX_COMPONENTS: usize = 128;
#[cfg(components_256)]
pub static MAX_COMPONENTS: usize = 256;
#[cfg(components_512)]
pub static MAX_COMPONENTS: usize = 512;
#[cfg(components_1024)]
pub static MAX_COMPONENTS: usize = 1024;
#[cfg(components_2048)]
pub static MAX_COMPONENTS: usize = 2048;
#[cfg(components_4096)]
pub static MAX_COMPONENTS: usize = 4096;

#[cfg(components_64)]
mod mask {
    pub type MaskType = u64;

    pub struct NextMask{
        next: u64,
        total_components: u8,
    }

    impl NextMask {
        pub fn new() -> NextMask {
            NextMask{
                next: 1,
                total_components: 0,
            }
        }

        #[inline]
        pub fn next(&mut self) -> MaskType{
            self.total_components += 1;
            if self.total_components > super::MAX_COMPONENTS as u8 {
                panic!("Trying to register more than {} components, please use the bigint feature in your cargo dependency", super::MAX_COMPONENTS);
            }
            let ret = self.next;
            self.next *= 2;
            ret
        }

        pub fn get(&self) -> MaskType {
            self.next
        }
    }

    pub const fn zero() -> MaskType{
        0
    }

    pub const fn one() -> MaskType{
        1
    }

    pub const fn two() -> MaskType{
        2
    }
}

#[cfg(components_bigint)]
mod mask{
    #[cfg(components_128)]
    pub type MaskType = numext_fixed_uint::U128;

    #[cfg(components_256)]
    pub type MaskType = numext_fixed_uint::U256;

    #[cfg(components_512)]
    pub type MaskType = numext_fixed_uint::U512;

    #[cfg(components_1024)]
    pub type MaskType = numext_fixed_uint::U1024;

    #[cfg(components_2048)]
    pub type MaskType = numext_fixed_uint::U2048;

    #[cfg(components_4096)]
    pub type MaskType = numext_fixed_uint::U4096;

    pub struct NextMask{
        next: MaskType,
        total_components: u16,
    }

    impl NextMask {
        pub fn new() -> NextMask {
            NextMask{
                next: MaskType::from(1u8),
                total_components: 0,
            }
        }

        #[inline]
        pub fn next(&mut self) -> MaskType{
            self.total_components += 1;
            if self.total_components > super::MAX_COMPONENTS as u16 {
                panic!("Trying to register more than {} components, please use a larger number of components feature in your cargo dependency", super::MAX_COMPONENTS);
            }
            let ret = self.next.clone();
            self.next *= MaskType::from(2u8);
            ret
        }

        pub fn get(&self) -> MaskType {
            self.next.clone()
        }
    }

    pub const fn zero() -> MaskType{
        MaskType::zero()
    }

    pub const fn one() -> MaskType{
        MaskType::one()
    }

    pub fn two() -> MaskType{
        MaskType::from(2u32)
    }
}

impl Default for NextMask{
    fn default() -> NextMask {
        NextMask::new()
    }
}

pub use self::mask::{MaskType, NextMask, zero, one, two};
use std::ops::Not;

#[derive(Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub enum Bitmask{
    All,
    Has(MaskType),
    Not(MaskType),
    Or(MaskType),
    Option(MaskType),
    HasNot(MaskType, MaskType),
    HasOr(MaskType, MaskType),
    NotOr(MaskType, MaskType),
    HasOption(MaskType, MaskType),
    OrOption(MaskType, MaskType),
    NotOption(MaskType, MaskType),
    HasNotOr(MaskType, MaskType, MaskType),
    HasNotOption(MaskType, MaskType, MaskType),
    HasOrOption(MaskType, MaskType, MaskType),
    NotOrOption(MaskType, MaskType, MaskType),
    HasNotOrOption(MaskType, MaskType, MaskType, MaskType),
    Refs(Vec<(component::Id, Bitmask)>),
    OtherAndRefs(Box<Bitmask>, Vec<(component::Id, Bitmask)>),
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Check{
    Yes,
    No,
    Refs(Vec<(component::Id, Bitmask)>),
}

impl<'a> From<bool> for Check{
    fn from(b: bool) -> Check{
        if b { Check::Yes } else { Check::No }
    }
}

impl Bitmask{
    #[inline]
    pub fn all() -> Bitmask {
        Bitmask::All
    }

    #[inline]
    pub fn option(option: MaskType) -> Bitmask {
        Bitmask::Option(option)
    }

    #[inline]
    pub fn has(has: MaskType) -> Bitmask {
        Bitmask::Has(has)
    }

    #[inline]
    pub fn not(not: MaskType) -> Bitmask {
        Bitmask::Not(not)
    }

    #[inline]
    pub fn has_not(has: MaskType, not: MaskType) -> Bitmask {
        Bitmask::HasNot(has, not)
    }

    #[inline]
    pub fn or(or: MaskType) -> Bitmask {
        Bitmask::Or(or)
    }

    pub fn reference<C: Component>(bitmask: Bitmask) -> Bitmask {
        Bitmask::Refs(vec![(C::id(), bitmask)])
    }

    pub fn components(&self) -> MaskType {
        match self {
            Bitmask::HasNot(has, not) => has | not,

            Bitmask::Has(has) => has.clone(),

            Bitmask::Not(not) => not.clone(),

            Bitmask::Or(or) => or.clone(),

            Bitmask::Option(option) => option.clone(),

            Bitmask::HasOr(has, or) => has | or,

            Bitmask::NotOr(not, or) => not | or,

            Bitmask::HasOption(has, option) => has | option,

            Bitmask::OrOption(or, option) => or | option,

            Bitmask::NotOption(not, option) => not | option,

            Bitmask::HasNotOr(has, not, or) => has | not | or,

            Bitmask::HasNotOption(has, not, option) => has | not | option,

            Bitmask::HasOrOption(has, or, option) => has | or | option,

            Bitmask::NotOrOption(not, or, option) => not | or | option,

            Bitmask::HasNotOrOption(has, not, or, option) => has | not | or | option,

            Bitmask::All => mask::zero(),

            Bitmask::Refs(_refs) => mask::zero(),

            Bitmask::OtherAndRefs(other, _refs) =>
                other.components()
        }
    }

    #[inline]
    pub fn check(&self, mask: MaskType) -> Check {
        match self {
            Bitmask::HasNot(has, not)
                | Bitmask::HasNotOption(has, not, _) =>
                    (mask.clone() & has.clone() == *has
                    && (mask.clone() ^ (not.clone().not())) & not.clone() == mask::zero()).into(),

            Bitmask::Has(has) | Bitmask::HasOption(has, _) =>
                (mask.clone() & has.clone() == *has).into(),

            Bitmask::Not(not) | Bitmask::NotOption(not, _) =>
                ((mask.clone() ^ (not.clone().not())) & not.clone() == mask::zero()).into(),

            Bitmask::Or(or) | Bitmask::OrOption(or, _) =>
                (mask.clone() & or.clone() != mask::zero()).into(),

            Bitmask::HasOr(has, or)
                | Bitmask::HasOrOption(has, or, _) =>
                    (mask.clone() & has.clone() == *has
                    && mask.clone() & or.clone() != mask::zero()).into(),

            Bitmask::NotOr(not, or)
                | Bitmask::NotOrOption(not, or, _) =>
                    ((mask.clone() ^ (not.clone().not())) & not.clone() == mask::zero()
                    && mask.clone() & or.clone() != mask::zero()).into(),

            Bitmask::HasNotOr(has, not, or)
                | Bitmask::HasNotOrOption(has, not, or, _) =>
                    ((mask.clone() & has.clone() == *has)
                    && ((mask.clone() ^ (not.clone().not())) & not.clone() == mask::zero())
                    && (mask.clone() & or.clone() != mask::zero())).into(),

            Bitmask::All | Bitmask::Option(_) => Check::Yes,

            Bitmask::Refs(refs) => Check::Refs(refs.clone()),

            Bitmask::OtherAndRefs(other, refs) => match other.check(mask) {
                Check::Yes => Check::Refs(refs.clone()),
                Check::No => Check::No,
                Check::Refs(more_refs) => {
                    let mut refs = refs.clone();
                    refs.extend_from_slice(&more_refs);
                    Check::Refs(refs)
                }
            }
        }
    }
}

impl BitOr for Bitmask{
    type Output = Bitmask;
    #[inline]
    fn bitor(self, rhs: Bitmask) -> Bitmask {
        use Bitmask::*;
        match (self, rhs){
            (Has(has), Has(rhs))   => Has(has | rhs),
            (Has(has), Not(rhs))   => HasNot(has, rhs),
            (Has(has), HasNot(rhs, rhs_not))      => HasNot(has | rhs, rhs_not),
            (Has(has), Or(rhs))    => HasOr(has, rhs),
            (Has(has), HasOr(rhs, rhs_or))      => HasOr(has | rhs, rhs_or),
            (Has(has), NotOr(rhs_not, rhs_or))    => HasNotOr(has, rhs_not, rhs_or),
            (Has(has), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(has | rhs, rhs_not, rhs_or),
            (Has(has), Option(option))        => HasOption(has, option),
            (Has(has), HasOption(rhs_has, rhs_option))        => HasOption(has | rhs_has, rhs_option),
            (Has(has), NotOption(rhs_not, rhs_option))      => HasNotOption(has, rhs_not, rhs_option),
            (Has(has), OrOption(rhs_or, rhs_option)) => HasOrOption(has, rhs_or, rhs_option),
            (Has(has), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(has | rhs_has, rhs_not, rhs_option),
            (Has(has), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(has | rhs_has, rhs_or, rhs_option),
            (Has(has), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, rhs_not, rhs_or, rhs_option),
            (Has(has), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, rhs_or, rhs_option),
            (Has(has), All)        => Has(has),

            // (Not(not), Has(rhs))   => HasNot(rhs, not),
            (Not(not), Not(rhs))   => Not(not | rhs),
            (Not(not), HasNot(rhs, rhs_not))      => HasNot(rhs, not | rhs_not),
            (Not(not), Or(rhs))    => NotOr(not, rhs),
            (Not(not), HasOr(rhs, rhs_or))      => HasNotOr(rhs, not, rhs_or),
            (Not(not), NotOr(rhs_not, rhs_or))    => NotOr(not | rhs_not, rhs_or),
            (Not(not), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(rhs, not | rhs_not, rhs_or),
            (Not(not), Option(option))        => NotOption(not, option),
            (Not(not), HasOption(rhs_has, rhs_option))        => HasNotOption(rhs_has, not, rhs_option),
            (Not(not), NotOption(rhs_not, rhs_option))      => NotOption(not | rhs_not, rhs_option),
            (Not(not), OrOption(rhs_or, rhs_option)) => NotOrOption(not, rhs_or, rhs_option),
            (Not(not), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(rhs_has, not | rhs_not, rhs_option),
            (Not(not), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not, rhs_or, rhs_option),
            (Not(not), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(not | rhs_not, rhs_or, rhs_option),
            (Not(not), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not | rhs_not, rhs_or, rhs_option),
            (Not(not), All)        => Not(not),

            // (HasNot(has, not), Has(rhs))   => HasNot(has | rhs, not),
            // (HasNot(has, not), Not(rhs))   => HasNot(has, not & rhs),
            (HasNot(has, not), HasNot(rhs, rhs_not))      => HasNot(has | rhs, not | rhs_not),
            (HasNot(has, not), Or(rhs))    => HasNotOr(has, not, rhs),
            (HasNot(has, not), HasOr(rhs, rhs_or))      => HasNotOr(has | rhs, not, rhs_or),
            (HasNot(has, not), NotOr(rhs_not, rhs_or))    => HasNotOr(has, not | rhs_not, rhs_or),
            (HasNot(has, not), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(has | rhs, not | rhs_not, rhs_or),
            (HasNot(has, not), Option(option))        => HasNotOption(has, not, option),
            (HasNot(has, not), HasOption(rhs_has, rhs_option))        => HasNotOption(has | rhs_has, not, rhs_option),
            (HasNot(has, not), NotOption(rhs_not, rhs_option))      => HasNotOption(has, not | rhs_not, rhs_option),
            (HasNot(has, not), OrOption(rhs_or, rhs_option)) => HasNotOrOption(has, not, rhs_or, rhs_option),
            (HasNot(has, not), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(has | rhs_has, not | rhs_not, rhs_option),
            (HasNot(has, not), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not, rhs_or, rhs_option),
            (HasNot(has, not), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, not | rhs_not, rhs_or, rhs_option),
            (HasNot(has, not), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not | rhs_not, rhs_or, rhs_option),
            (HasNot(has, not), All)        => HasNot(has, not),

            // (Or(or), Has(rhs))   => HasOr(rhs, or),
            // (Or(or), Not(rhs))   => NotOr(rhs, or),
            // (Or(or), HasNot(rhs, rhs_not))      => HasNotOr(rhs, rhs_not, or),
            (Or(or), Or(rhs))    => Or(or | rhs),
            (Or(or), HasOr(rhs, rhs_or))      => HasOr(rhs, or | rhs_or),
            (Or(or), NotOr(rhs_not, rhs_or))    => NotOr(rhs_not, or | rhs_or),
            (Or(or), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(rhs, rhs_not, or | rhs_or),
            (Or(or), Option(option)) => OrOption(or, option),
            (Or(or), HasOption(rhs_has, rhs_option))        => HasOrOption(rhs_has, or, rhs_option),
            (Or(or), NotOption(rhs_not, rhs_option))      => NotOrOption(rhs_not, or, rhs_option),
            (Or(or), OrOption(rhs_or, rhs_option)) => OrOption(or | rhs_or, rhs_option),
            (Or(or), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(rhs_has, rhs_not, or, rhs_option),
            (Or(or), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(rhs_has, or | rhs_or, rhs_option),
            (Or(or), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(rhs_not, or | rhs_or, rhs_option),
            (Or(or), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, rhs_not, or | rhs_or, rhs_option),
            (Or(or), All)        => Or(or),

            // (HasOr(has, or), Has(rhs))   => HasOr(has | rhs, or),
            // (HasOr(has, or), Not(rhs))   => HasNotOr(has, rhs, or),
            // (HasOr(has, or), HasNot(rhs, rhs_not))      => HasNotOr(has | rhs, rhs_not, or),
            // (HasOr(has, or), Or(rhs))    => HasOr(has, or | rhs),
            (HasOr(has, or), HasOr(rhs, rhs_or))      => HasOr(has | rhs, or | rhs_or),
            (HasOr(has, or), NotOr(rhs_not, rhs_or))    => HasNotOr(has, rhs_not, or | rhs_or),
            (HasOr(has, or), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(has | rhs, rhs_not, or | rhs_or),
            (HasOr(has, or), Option(option)) => HasOrOption(has, or, option),
            (HasOr(has, or), HasOption(rhs_has, rhs_option))        => HasOrOption(has | rhs_has, or, rhs_option),
            (HasOr(has, or), NotOption(rhs_not, rhs_option))      => HasNotOrOption(has, rhs_not, or, rhs_option),
            (HasOr(has, or), OrOption(rhs_or, rhs_option)) => HasOrOption(has, or | rhs_or, rhs_option),
            (HasOr(has, or), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, or, rhs_option),
            (HasOr(has, or), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(has | rhs_has, or | rhs_or, rhs_option),
            (HasOr(has, or), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, rhs_not, or | rhs_or, rhs_option),
            (HasOr(has, or), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, or | rhs_or, rhs_option),
            (HasOr(has, or), All)        => HasOr(has, or),

            // (NotOr(not, or), Has(rhs))   => HasNotOr(rhs, not, or),
            // (NotOr(not, or), Not(rhs))   => NotOr(not & rhs, or),
            // (NotOr(not, or), HasNot(rhs, rhs_not))      => HasNotOr(rhs, not & rhs_not, or),
            // (NotOr(not, or), Or(rhs))    => NotOr(not, or | rhs),
            // (NotOr(not, or), HasOr(rhs, rhs_or))      => HasNotOr(rhs, not, or | rhs_or),
            (NotOr(not, or), NotOr(rhs_not, rhs_or))    => NotOr(not | rhs_not, or | rhs_or),
            (NotOr(not, or), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(rhs, not | rhs_not, or | rhs_or),
            (NotOr(not, or), Option(option)) => NotOrOption(not, or, option),
            (NotOr(not, or), HasOption(rhs_has, rhs_option))        => HasNotOrOption(rhs_has, not, or, rhs_option),
            (NotOr(not, or), NotOption(rhs_not, rhs_option))      => NotOrOption(not | rhs_not, or, rhs_option),
            (NotOr(not, or), OrOption(rhs_or, rhs_option)) => NotOrOption(not, or | rhs_or, rhs_option),
            (NotOr(not, or), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(rhs_has, not | rhs_not, or, rhs_option),
            (NotOr(not, or), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not, or | rhs_or, rhs_option),
            (NotOr(not, or), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(not | rhs_not, or | rhs_or, rhs_option),
            (NotOr(not, or), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not | rhs_not, or | rhs_or, rhs_option),
            (NotOr(not, or), All)        => NotOr(not, or),

            // (HasNotOr(has, not, or), Has(rhs))   => HasNotOr(has | rhs, not, or),
            // (HasNotOr(has, not, or), Not(rhs))   => HasNotOr(has, not & rhs, or),
            // (HasNotOr(has, not, or), HasNot(rhs, rhs_not))      => HasNotOr(has | rhs, not & rhs_not, or),
            // (HasNotOr(has, not, or), Or(rhs))    => HasNotOr(has, not, or | rhs),
            // (HasNotOr(has, not, or), HasOr(rhs, rhs_or))      => HasNotOr(has | rhs, not, or | rhs_or),
            // (HasNotOr(has, not, or), NotOr(rhs_not, rhs_or))    => HasNotOr(has, not & rhs_not, or | rhs_or),
            (HasNotOr(has, not, or), HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(has | rhs, not | rhs_not, or | rhs_or),
            (HasNotOr(has, not, or), Option(option)) => HasNotOrOption(has, not, or, option),
            (HasNotOr(has,not, or), HasOption(rhs_has, rhs_option))        => HasNotOrOption(has | rhs_has, not, or, rhs_option),
            (HasNotOr(has,not, or), NotOption(rhs_not, rhs_option))      => HasNotOrOption(has, not | rhs_not, or, rhs_option),
            (HasNotOr(has,not, or), OrOption(rhs_or, rhs_option)) => HasNotOrOption(has, not, or | rhs_or, rhs_option),
            (HasNotOr(has,not, or), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(has | rhs_has, not | rhs_not, or, rhs_option),
            (HasNotOr(has,not, or), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not, or | rhs_or, rhs_option),
            (HasNotOr(has,not, or), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, not | rhs_not, or | rhs_or, rhs_option),
            (HasNotOr(has,not, or), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not | rhs_not, or | rhs_or, rhs_option),
            (HasNotOr(has, not, or), All)        => HasNotOr(has, not, or),

            (Option(option), Option(rhs_option)) => Option(option | rhs_option),
            (Option(option), HasOption(rhs_has, rhs_option))        => HasOption(rhs_has, option | rhs_option),
            (Option(option), NotOption(rhs_not, rhs_option))      => NotOption(rhs_not, option | rhs_option),
            (Option(option), OrOption(rhs_or, rhs_option)) => OrOption(rhs_or, option | rhs_option),
            (Option(option), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(rhs_has, rhs_not, option | rhs_option),
            (Option(option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(rhs_has, rhs_or, option | rhs_option),
            (Option(option), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(rhs_not, rhs_or, option | rhs_option),
            (Option(option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, rhs_not, rhs_or, option | rhs_option),
            (Option(option), All) => Option(option),

            (HasOption(has, option), HasOption(rhs_has, rhs_option)) => HasOption(has | rhs_has, option | rhs_option),
            (HasOption(has, option), NotOption(rhs_not, rhs_option))      => HasNotOption(has, rhs_not, option | rhs_option),
            (HasOption(has, option), OrOption(rhs_or, rhs_option)) => HasOrOption(has, rhs_or, option | rhs_option),
            (HasOption(has, option), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(has | rhs_has, rhs_not, option | rhs_option),
            (HasOption(has, option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(has | rhs_has, rhs_or, option | rhs_option),
            (HasOption(has, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, rhs_not, rhs_or, option | rhs_option),
            (HasOption(has, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, rhs_or, option | rhs_option),
            (HasOption(has, option), All) => HasOption(has, option),

            (NotOption(not, option), NotOption(rhs_not, rhs_option)) => NotOption(not | rhs_not, option | rhs_option),
            (NotOption(not, option), OrOption(rhs_or, rhs_option)) => NotOrOption(not, rhs_or, option | rhs_option),
            (NotOption(not, option), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOption(rhs_has, not | rhs_not, option | rhs_option),
            (NotOption(not, option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not, rhs_or, option | rhs_option),
            (NotOption(not, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(not | rhs_not, rhs_or, option | rhs_option),
            (NotOption(not, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not | rhs_not, rhs_or, option | rhs_option),
            (NotOption(not, option), All) => NotOption(not, option),


            (OrOption(or, option), OrOption(rhs_or, rhs_option)) => OrOption(or | rhs_or, option | rhs_option),
            (OrOption(or, option), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(rhs_has, rhs_not, or, option | rhs_option),
            (OrOption(or, option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(rhs_has, or | rhs_or, option | rhs_option),
            (OrOption(or, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(rhs_not, or | rhs_or, option | rhs_option),
            (OrOption(or, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, rhs_not, or | rhs_or, option | rhs_option),
            (OrOption(or, option), All) => OrOption(or, option),


            (HasNotOption(has, or, option), HasNotOption(rhs_has, rhs_not, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, or, option | rhs_option),
            (HasNotOption(has, not, option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not, rhs_or, option | rhs_option),
            (HasNotOption(has, not, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, not | rhs_not, rhs_or, option | rhs_option),
            (HasNotOption(has, not, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not | rhs_not, rhs_or, option | rhs_option),
            (HasNotOption(has, not, option), All) => HasNotOption(has, not, option),

            (HasOrOption(has, or, option), HasOrOption(rhs_has, rhs_or, rhs_option)) => HasOrOption(has | rhs_has, or | rhs_or, option | rhs_option),
            (HasOrOption(has, or, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has, rhs_not, or | rhs_or, option | rhs_option),
            (HasOrOption(has, or, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, rhs_not, or | rhs_or, option | rhs_option),
            (HasOrOption(has, or, option), All) => HasOrOption(has, or, option),


            (NotOrOption(not, or, option), NotOrOption(rhs_not, rhs_or, rhs_option)) => NotOrOption(not | rhs_not, or | rhs_or, option | rhs_option),
            (NotOrOption(not, or, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(rhs_has, not | rhs_not, or | rhs_or, option | rhs_option),
            (NotOrOption(not, or, option), All) => NotOrOption(not, or, option),


            (HasNotOrOption(has, not, or, option), HasNotOrOption(rhs_has, rhs_not, rhs_or, rhs_option)) => HasNotOrOption(has | rhs_has, not | rhs_not, or | rhs_or, option | rhs_option),
            (HasNotOrOption(has, not, or, option), All) => HasNotOrOption(has, not, or, option),

            // (All, Has(rhs))   => Has(rhs),
            // (All, Not(rhs))   => Not(rhs),
            // (All, HasNot(rhs, rhs_not))    => HasNot(rhs, rhs_not),
            // (All, Or(rhs))    => Or(rhs),
            // (All, HasOr(rhs, rhs_or))    => HasNot(rhs, rhs_or),
            // (All, NotOr(rhs_not, rhs_or))    => HasNot(rhs_not, rhs_or),
            // (All, HasNotOr(rhs, rhs_not, rhs_or))    => HasNotOr(rhs, rhs_not, rhs_or),
            (All, All)        => All,

            (Refs(mut refs), Refs(rhs_refs)) => {
                refs.extend_from_slice(&rhs_refs);
                Refs(refs)
            },
            (other, Refs(refs)) => OtherAndRefs(Box::new(other), refs),
            (other, OtherAndRefs(rhs_other, refs)) => OtherAndRefs(Box::new(other | *rhs_other), refs),

            (lhs, rhs)        => rhs.bitor(lhs)
        }
    }
}