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
//! Helper module to compute whether a combination of types implementing
//! [`crate::TypeLayout`] are
//! [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited) or
//! [uninhabited](https://doc.rust-lang.org/reference/glossary.html#uninhabited).

#![allow(clippy::undocumented_unsafe_blocks)]

/// Marker type used to specify that a type implementing
/// [`crate::TypeLayout::Inhabited`] is
/// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
pub struct Inhabited;

unsafe impl crate::TypeLayout for Inhabited {
    type Inhabited = Self;

    const TYPE_LAYOUT: crate::TypeLayoutInfo<'static> = crate::TypeLayoutInfo {
        name: ::core::any::type_name::<Self>(),
        size: ::core::mem::size_of::<Self>(),
        alignment: ::core::mem::align_of::<Self>(),
        structure: crate::TypeStructure::Struct {
            repr: "",
            fields: &[],
        },
    };
}

unsafe impl crate::typeset::ComputeTypeSet for Inhabited {
    type Output<T: crate::typeset::ExpandTypeSet> = crate::typeset::tset![.. @ T];
}

#[allow(clippy::empty_enum)]
/// Marker type used to specify that a type implementing
/// [`crate::TypeLayout::Inhabited`] is
/// [uninhabited](https://doc.rust-lang.org/reference/glossary.html#uninhabited).
pub enum Uninhabited {}

unsafe impl crate::TypeLayout for Uninhabited {
    type Inhabited = Self;

    const TYPE_LAYOUT: crate::TypeLayoutInfo<'static> = crate::TypeLayoutInfo {
        name: ::core::any::type_name::<Self>(),
        size: ::core::mem::size_of::<Self>(),
        alignment: ::core::mem::align_of::<Self>(),
        structure: crate::TypeStructure::Enum {
            repr: "",
            variants: &[],
        },
    };
}

unsafe impl crate::typeset::ComputeTypeSet for Uninhabited {
    type Output<T: crate::typeset::ExpandTypeSet> = crate::typeset::tset![.. @ T];
}

#[allow(clippy::module_name_repetitions)]
#[doc(hidden)]
pub trait ComputeInhabited: sealed::ComputeInhabited {
    type Output: OutputMaybeInhabited;
}

#[allow(clippy::module_name_repetitions)]
#[doc(hidden)]
pub trait OutputMaybeInhabited:
    ComputeInhabited + crate::TypeGraphLayout + sealed::OutputMaybeInhabited
{
}

mod sealed {
    pub trait ComputeInhabited {}
    pub trait OutputMaybeInhabited {}
}

impl sealed::ComputeInhabited for Inhabited {}
impl ComputeInhabited for Inhabited {
    type Output = Self;
}
impl sealed::OutputMaybeInhabited for Inhabited {}
impl OutputMaybeInhabited for Inhabited {}

impl sealed::ComputeInhabited for Uninhabited {}
impl ComputeInhabited for Uninhabited {
    type Output = Self;
}
impl sealed::OutputMaybeInhabited for Uninhabited {}
impl OutputMaybeInhabited for Uninhabited {}

mod logical {
    use super::{sealed, ComputeInhabited, Inhabited, Uninhabited};

    pub struct And<L: ComputeInhabited, R: ComputeInhabited> {
        _left: L,
        _right: R,
    }

    impl<L: ComputeInhabited, R: ComputeInhabited> sealed::ComputeInhabited for And<L, R> {}
    impl<L: ComputeInhabited, R: ComputeInhabited> ComputeInhabited for And<L, R> {
        default type Output = Uninhabited;
    }

    impl<L: ComputeInhabited<Output = Inhabited>, R: ComputeInhabited<Output = Inhabited>>
        ComputeInhabited for And<L, R>
    {
        type Output = Inhabited;
    }

    pub struct Or<L: ComputeInhabited, R: ComputeInhabited> {
        _left: L,
        _right: R,
    }

    impl<L: ComputeInhabited, R: ComputeInhabited> sealed::ComputeInhabited for Or<L, R> {}
    impl<L: ComputeInhabited, R: ComputeInhabited> ComputeInhabited for Or<L, R> {
        default type Output = Inhabited;
    }

    impl<L: ComputeInhabited<Output = Uninhabited>, R: ComputeInhabited<Output = Uninhabited>>
        ComputeInhabited for Or<L, R>
    {
        type Output = Uninhabited;
    }
}

/// Helper macro to compute whether all of a list of types, all implementing
/// [`crate::TypeLayout`], e.g. `[T, U, V]`, are
/// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
/// For instance, a struct is inhabited iff all of its fields are inhabited.
/// The empty list of types is inhabited. This macro resolves into either
/// [`Inhabited`] or [`Uninhabited`].
pub macro all {
    () => { Inhabited },
    ($L:ty $(, $R:ty)*) => {
        <logical::And<<$L as $crate::TypeLayout>::Inhabited, all![$($R),*]> as ComputeInhabited>::Output
    },
}

/// Helper macro to compute whether any of a list of types, all implementing
/// [`crate::TypeLayout`], e.g. `[T, U, V]`, is
/// [inhabited](https://doc.rust-lang.org/reference/glossary.html#inhabited).
/// For instance, an enum is inhabited iff any of its variants is inhabited.
/// The empty list of types is
/// [uninhabited](https://doc.rust-lang.org/reference/glossary.html#uninhabited).
/// This macro resolves into either [`Inhabited`] or [`Uninhabited`].
pub macro any {
    () => { Uninhabited },
    ($L:ty $(, $R:ty)*) => {
        <logical::Or<<$L as $crate::TypeLayout>::Inhabited, any![$($R),*]> as ComputeInhabited>::Output
    },
}