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
use core::{
    fmt,
    hash::{Hash, Hasher},
    num::NonZeroUsize,
    ptr,
};

use awint_internals::*;
use const_fn::const_fn;

use crate::Bits;

// `InlAwi` has two parameters, because we absolutely have to have a parameter
// that directly specifies the raw array length, and because we also want Rust's
// typechecking to distinguish between different bitwidth `InlAwi`s.

/// An arbitrary width integer with const generic bitwidth that can be stored
/// inline on the stack like an array.
///
/// **NOTE**: Ideally, you could just type
/// `let _: InlAwi<100> = InlAwi<100>::zero();` if you wanted to specify and
/// construct an `InlAwi` type with bitwidth 100. However, Rust's lack of custom
/// DST support and const generics limitations makes this currently impossible.
/// The two const generic parameters of an `InlAwi` are part of a workaround for
/// this. Typing out a
/// `let _: InlAwi<BW, LEN> = InlAwi<BW, LEN>::zero()` should not be
/// done directly because it is non-portable and relies on unstable internal
/// details. Instead, you should use
///
/// `let _: inlawi_ty!(100) = inlawi!(0u100);` or `let _ =
/// <inlawi_ty!(100)>::zero();` using macros from the `awint_macros` crate.
///
/// See the crate level documentation of `awint_macros` for more macros and
/// information.
///
/// This struct implements `Deref<Target = Bits>`, see the main documentation of
/// [Bits](crate::Bits) for more. There are also some allocating functions that
/// only `ExtAwi` and `Awi` implement.
///
/// ```
/// use awint::{cc, inlawi, inlawi_ty, Bits, InlAwi};
///
/// fn example(mut lhs: &mut Bits, rhs: &Bits) {
///     // `InlAwi` stored on the stack does no allocation
///     let mut tmp = inlawi!(0i100);
///     tmp.mul_add_(lhs, rhs).unwrap();
///     cc!(tmp; lhs).unwrap();
/// }
///
/// let val: inlawi_ty!(100) = {
///     let mut x = inlawi!(123i100);
///     let y = inlawi!(2i100);
///     x.neg_(true);
///     example(&mut x, &y);
///     x
/// };
/// let x: &Bits = &val;
///
/// assert_eq!(x, inlawi!(-246i100).as_ref());
/// ```
// FIXME
/// ```text
/// // note: see README because this is broken on some nightlies
///
/// // only needed if you are trying to use in `const` contexts
/// #![feature(const_trait_impl)]
/// #![feature(const_mut_refs)]
/// #![feature(const_option)]
/// use awint::{cc, inlawi, inlawi_ty, Bits, InlAwi};
///
/// const fn const_example(mut lhs: &mut Bits, rhs: &Bits) {
///     // `InlAwi` stored on the stack does no allocation
///     let mut tmp = inlawi!(0i100);
///     tmp.mul_add_(lhs, rhs).unwrap();
///     cc!(tmp; lhs).unwrap();
/// }
///
/// // Because `InlAwi`'s construction functions are `const`, we can make full
/// // use of `Bits` `const` abilities
/// const AWI: inlawi_ty!(100) = {
///     let mut x = inlawi!(123i100);
///     let y = inlawi!(2i100);
///     x.neg_(true);
///     const_example(&mut x, &y);
///     x
/// };
/// const X: &'static Bits = &AWI;
///
/// assert_eq!(X, inlawi!(-246i100).as_ref());
/// ```
#[repr(C)]
#[derive(Clone, Copy)] // following what arrays do
pub struct InlAwi<const BW: usize, const LEN: usize> {
    _raw_stack_bits: RawStackBits<BW, LEN>,
}

/// `InlAwi` is safe to send between threads since it does not own
/// aliasing memory and has no reference counting mechanism like `Rc`.
unsafe impl<const BW: usize, const LEN: usize> Send for InlAwi<BW, LEN> {}

/// `InlAwi` is safe to share between threads since it does not own
/// aliasing memory and has no mutable internal state like `Cell` or `RefCell`.
unsafe impl<const BW: usize, const LEN: usize> Sync for InlAwi<BW, LEN> {}

impl<'a, const BW: usize, const LEN: usize> InlAwi<BW, LEN> {
    /// Returns a reference to `self` in the form of `&Bits`.
    #[inline]
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub(in crate::data) const fn internal_as_ref(&'a self) -> &'a Bits {
        // Safety: Only functions like `unstable_from_u8_slice` can construct the
        // `_raw_stack_bits` field on `InlAwi`s. The `RawStackBits` functions
        // checks to insure the raw invariants. The explicit lifetimes make sure they do
        // not become unbounded.
        unsafe { Bits::from_raw_parts(self._raw_stack_bits.to_raw_bits()) }
    }

    /// Returns a reference to `self` in the form of `&mut Bits`.
    #[inline]
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub(in crate::data) const fn internal_as_mut(&'a mut self) -> &'a mut Bits {
        // Safety: Same as `internal_as_ref`, except we use `to_raw_bits_mut` so that
        // the pointer tag is not `Frozen`
        unsafe { Bits::from_raw_parts_mut(self._raw_stack_bits.to_raw_bits_mut()) }
    }

    /// Returns the bitwidth of this type of `InlAwi` as a `NonZeroUsize`
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub const fn const_nzbw() -> NonZeroUsize {
        RawStackBits::<BW, LEN>::nzbw()
    }

    /// Returns the bitwidth of this type of `InlAwi` as a `usize`
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub const fn const_bw() -> usize {
        RawStackBits::<BW, LEN>::bw()
    }

    /// The same as `Self::const_nzbw()` except that it takes `&self`, this
    /// exists to help with macros
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub const fn nzbw(&self) -> NonZeroUsize {
        Self::const_nzbw()
    }

    /// The same as `Self::const_bw()` except that it takes `&self`, this exists
    /// to help with macros
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub const fn bw(&self) -> usize {
        Self::const_bw()
    }

    /// Returns the exact number of `Digit`s needed to store all bits.
    #[const_fn(cfg(feature = "const_support"))]
    #[must_use]
    pub const fn total_digits(&self) -> usize {
        // TODO use `NonZeroUsize` in the `len` and `total_digits` returns?
        RawStackBits::<BW, LEN>::total_digits().get()
    }

    /// This is not intended for direct use, use `awint_macros::inlawi`
    /// or some other constructor instead. The purpose of this function is to
    /// allow for a `Digit::BITS` difference between a target architecture and
    /// the build architecture. Uses `u8_slice_`.
    #[doc(hidden)]
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn unstable_from_u8_slice(buf: &[u8]) -> Self {
        let mut val = InlAwi {
            _raw_stack_bits: RawStackBits::zero(),
        };

        // At this point, we would call `val.u8_slice_(buf)` and could return that.
        // However, we run into a problem where the compiler has difficulty. For
        // example,
        //
        // ```
        // pub fn internal(x: &mut Bits, neg: bool) {
        //     let y = inlawi!(-3858683298722959599393.23239873423987_i1024f512);
        //     x.neg_add_(neg, &y).unwrap();
        // }
        // ```
        //
        // should compile into a function that reserves 128 bytes (plus 32 or so more
        // depending on architecture) on the stack pointer, a single
        // memcpy, and then a call to `neg_add_`. However, if we don't inline
        // most functions it will get confused, reserve a further 128 bytes, add
        // a memcpy, and a memset. This is bad in general but very bad for architectures
        // like AVR, where we don't want to double stack reservations.

        // inline `u8_slice_`, but we can also eliminate the `digit_set`
        let self_byte_width = val.total_digits() * DIGIT_BYTES;
        let min_width = if self_byte_width < buf.len() {
            self_byte_width
        } else {
            buf.len()
        };
        // start of digits that will not be completely overwritten
        let start = min_width / DIGIT_BYTES;
        unsafe {
            // zero out first.
            // (skip because we initialized `raw` to all zeros)
            //val.digit_set(false, start..self.total_digits(), false);
            // Safety: `src` is valid for reads at least up to `min_width`, `dst` is valid
            // for writes at least up to `min_width`, they are aligned, and are
            // nonoverlapping because `self` is a mutable reference.
            ptr::copy_nonoverlapping(
                buf.as_ptr(),
                // note that we marked this as `#[inline]`
                val.as_mut_bytes_full_width_nonportable().as_mut_ptr(),
                min_width,
            );
            // `start` can be `self.total_digits()`, so cap it
            let cap = if start >= val.total_digits() {
                val.total_digits()
            } else {
                start + 1
            };
            const_for!(i in {0..cap} {
                // correct for big endian, otherwise no-op
                *val.get_unchecked_mut(i) = Digit::from_le(val.get_unchecked(i));
            });
        }
        val.clear_unused_bits();

        val
    }

    /// Zero-value construction with bitwidth `BW`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn zero() -> Self {
        Self {
            _raw_stack_bits: RawStackBits::zero(),
        }
    }

    /// Unsigned-maximum-value construction with bitwidth `BW`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn umax() -> Self {
        let mut val = Self {
            _raw_stack_bits: RawStackBits::all_set(),
        };
        val.const_as_mut().clear_unused_bits();
        val
    }

    /// Signed-maximum-value construction with bitwidth `BW`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn imax() -> Self {
        let mut val = Self::umax();
        *val.const_as_mut().last_mut() = (MAX >> 1) >> val.unused();
        val
    }

    /// Signed-minimum-value construction with bitwidth `BW`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn imin() -> Self {
        let mut val = Self::zero();
        *val.const_as_mut().last_mut() = (IDigit::MIN as Digit) >> val.unused();
        val
    }

    /// Unsigned-one-value construction with bitwidth `BW`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn uone() -> Self {
        let mut val = Self::zero();
        *val.const_as_mut().first_mut() = 1;
        val
    }

    /// Used for tests, Can't put in `awint_internals`
    #[doc(hidden)]
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn assert_invariants(this: &Self) {
        // double check
        RawStackBits::<BW, LEN>::_assert_invariants();
        // not a strict invariant but we want to test it
        this.assert_cleared_unused_bits();
    }
}

/// If `self` and `other` have unmatching bit widths, `false` will be returned.
impl<const BW: usize, const LEN: usize> PartialEq for InlAwi<BW, LEN> {
    fn eq(&self, rhs: &Self) -> bool {
        self.as_ref() == rhs.as_ref()
    }
}

/// If `self` and `other` have unmatching bit widths, `false` will be returned.
impl<const BW: usize, const LEN: usize> Eq for InlAwi<BW, LEN> {}

#[cfg(feature = "zeroize_support")]
impl<const BW: usize, const LEN: usize> zeroize::Zeroize for InlAwi<BW, LEN> {
    fn zeroize(&mut self) {
        self.as_mut().zeroize()
    }
}

macro_rules! impl_fmt {
    ($($ty:ident)*) => {
        $(
            impl<const BW: usize, const LEN: usize> fmt::$ty for InlAwi<BW, LEN> {
                /// Forwards to the corresponding impl for `Bits`
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                    fmt::$ty::fmt(self.as_ref(), f)
                }
            }
        )*
    };
}

impl_fmt!(Debug Display LowerHex UpperHex Octal Binary);

impl<const BW: usize, const LEN: usize> Hash for InlAwi<BW, LEN> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_ref().hash(state);
    }
}

impl InlAwi<1, { Bits::unstable_raw_digits(1) }> {
    /// Creates an `InlAwi` with one bit set to this `bool`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn from_bool(x: bool) -> Self {
        let mut val = Self::zero();
        val.bool_(x);
        val
    }
}

macro_rules! inlawi_from {
    ($($w:expr, $u:ident $from_u:ident $u_:ident
        $i:ident $from_i:ident $i_:ident);*;) => {
        $(
            impl InlAwi<$w, {Bits::unstable_raw_digits($w)}> {
                /// Creates an `InlAwi` with the same bitwidth and bits as the integer
                #[const_fn(cfg(feature = "const_support"))]
                pub const fn $from_u(x: $u) -> Self {
                    let mut val = Self::zero();
                    val.$u_(x);
                    val
                }

                /// Creates an `InlAwi` with the same bitwidth and bits as the integer
                #[const_fn(cfg(feature = "const_support"))]
                pub const fn $from_i(x: $i) -> Self {
                    let mut val = Self::zero();
                    val.$i_(x);
                    val
                }
            }
        )*
    };
}

inlawi_from!(
    8, u8 from_u8 u8_ i8 from_i8 i8_;
    16, u16 from_u16 u16_ i16 from_i16 i16_;
    32, u32 from_u32 u32_ i32 from_i32 i32_;
    64, u64 from_u64 u64_ i64 from_i64 i64_;
    128, u128 from_u128 u128_ i128 from_i128 i128_;
);

pub(crate) type UsizeInlAwi = InlAwi<{ USIZE_BITS }, { Bits::unstable_raw_digits(USIZE_BITS) }>;

impl UsizeInlAwi {
    /// Creates an `InlAwi` with the same bitwidth and bits as the integer
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn from_usize(x: usize) -> Self {
        let mut val = Self::zero();
        val.usize_(x);
        val
    }

    /// Creates an `InlAwi` with the same bitwidth and bits as the integer
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn from_isize(x: isize) -> Self {
        let mut val = Self::zero();
        val.isize_(x);
        val
    }
}

pub(crate) type DigitInlAwi = InlAwi<{ BITS }, { Bits::unstable_raw_digits(BITS) }>;

impl DigitInlAwi {
    /// Creates an `InlAwi` with the same bitwidth and bits as `Digit`
    #[const_fn(cfg(feature = "const_support"))]
    pub const fn from_digit(x: Digit) -> Self {
        let mut val = Self::zero();
        val.digit_(x);
        val
    }
}