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
//! See [`AuxOptions`].

use core::ffi::{
	CStr,
	c_char
};
use core::marker::PhantomData;
use core::mem::{
	transmute, MaybeUninit
};
use core::ptr::null;
use core::slice::from_raw_parts;

/// List of string options to be used with
/// [`Thread::check_option`](crate::Thread::check_option).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct AuxOptions<'str, const N: usize> {
	pub options: [*const c_char; N],
	terminator: *const c_char,
	_life: PhantomData<&'str CStr>
}

impl<'str, const N: usize> AuxOptions<'str, N> {
	/// Construct an instance of [`AuxOptions`] with a static list of options.
	pub const fn new(items: [&'str CStr; N]) -> Self {
		// SAFETY: We make an uninit `[*const c_char; N]`, but then immediately
		// fill it with stuff without reading from it.
		let regs: [*const c_char; N] = unsafe {
			let mut dest: [*const c_char; N] = MaybeUninit::uninit().assume_init();
	
			let mut i = 0;
			while i < N {
				dest[i] = items[i].as_ptr();
				i += 1;
			}

			dest
		};

		Self {
			options: regs,
			terminator: null(),
			_life: PhantomData
		}
	}

	/// Return the number of options that this list has.
	pub const fn count() -> usize {
		N
	}

	/// Return a pointer to this structure to be used with FFI.
	pub const fn as_ptr(&self) -> *const *const c_char {
		unsafe { transmute(self as *const _) }
	}

	/// Return a slice of [`*const c_char`](c_char)s that represent the string
	/// options contained within the structure.
	pub const fn as_str_ptr_slice(&self) -> &[*const c_char] {
		unsafe { from_raw_parts(
			transmute(self as *const _ as *const c_char), N + 1
		) }
	}
}