How should Assume values be created, combined?

To initialize and combine Assume values, this proposal defines a set of associated constants and an Add impl:

impl Assume {
    pub const NOTHING: Self = Self {
        alignment   : false,
        lifetimes   : false,
        validity    : false,
        visibility  : false,
    };

    pub const ALIGNMENT:  Self = Self {alignment: true, ..Self::NOTHING};
    pub const LIFETIMES:  Self = Self {lifetimes: true, ..Self::NOTHING};
    pub const VALIDITY:   Self = Self {validity:  true, ..Self::NOTHING};
    pub const VISIBILITY: Self = Self {validity:  true, ..Self::NOTHING};
}

impl const core::ops::Add for Assume {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            alignment   : self.alignment  || other.alignment,
            lifetimes   : self.lifetimes  || other.lifetimes,
            validity    : self.validity   || other.validity,
            visibility  : self.visibility || other.visibility,
        }
    }
}

Consequently, Assume values can be ergonomically created (e.g., Assume::ALIGNMENT) and combined (e.g., Assume::ALIGNMENT + Assume::VALIDITY + ASSUME).

Let's contrast this approach with two other possibilities:

Alternative: Minimalism

Alternatively, we might only provide:

impl Assume {
    pub const NOTHING: Self = Self {
        alignment   : false,
        lifetimes   : false,
        validity    : false,
        visibility  : false,
    };
}

This is the minimum impl we must provide for Assume to be useful. With it, Assume values can be created:


#![allow(unused)]
fn main() {
const ASSUME_ALIGNMENT: Assume = {
  let mut assume = Assume::NOTHING;
  assume.alignment = true;
  assume
};
}

and combined:


#![allow(unused)]
fn main() {
const ALSO_ASSUME_ALIGNMENT_VALIDITY: Assume = {
  let mut assume = ASSUME;
  assume.alignment = true;
  assume.validity = true;
  assume
};
}

This approach achieves minimalism at the cost of ergonomics.

Alternative: Builder Methods

Alternatively, we could define chainable builder methods:

impl Assume {
    pub const NOTHING: Self = Assume {
        alignment   : false,
        lifetimes   : false,
        validity    : false,
        visibility  : false,
    };

    pub const fn alignment(self)  -> Self { Assume { alignment:  true, ..self } }
    pub const fn lifetimes(self)  -> Self { Assume { lifetimes:  true, ..self } }
    pub const fn validity(self)   -> Self { Assume { validity:   true, ..self } }
    pub const fn visibility(self) -> Self { Assume { visibility: true, ..self } }
}

With this, Assume values can be created:

Assume::NOTHING.alignment()

...and combined:

ASSUME.alignment().validity()

This approach is almost as succinct as the approach selected by this proposal (i.e., the Add impl), but meaning of the resulting expressions are not quite as self-evident.