use core::{ffi::c_int, num::NonZero};
use crate::error::{Error, Result};
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
#[repr(transparent)]
pub struct BindIndex(NonZero<c_int>);
impl BindIndex {
pub const INITIAL: Self = Self(NonZero::new(1).unwrap());
pub const fn new(value: c_int) -> Result<Self, ()> {
match NonZero::new(value) {
Some(value) => Ok(Self(value)),
None => Err(Error::range()),
}
}
pub const unsafe fn new_unchecked(value: c_int) -> Self {
Self(unsafe { NonZero::new_unchecked(value) })
}
#[inline]
pub const fn value(&self) -> c_int {
self.0.get()
}
pub const fn iter(&self) -> BindIndexes {
BindIndexes::new(*self)
}
pub const fn next(&self) -> Self {
unsafe { Self::new_unchecked(self.value() + 1) }
}
}
impl IntoIterator for BindIndex {
type Item = BindIndex;
type IntoIter = BindIndexes;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl From<BindIndex> for i32 {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl From<BindIndex> for u32 {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl From<BindIndex> for i64 {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl From<BindIndex> for u64 {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl From<BindIndex> for isize {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl From<BindIndex> for usize {
fn from(index: BindIndex) -> Self {
index.value() as Self
}
}
impl TryFrom<i32> for BindIndex {
type Error = Error<()>;
fn try_from(value: i32) -> Result<Self, ()> {
if value <= 0 {
Err(Error::range())
} else {
Self::new(value as c_int)
}
}
}
impl TryFrom<i64> for BindIndex {
type Error = Error<()>;
fn try_from(value: i64) -> Result<Self, ()> {
match c_int::try_from(value) {
Ok(value) if value > 0 => Self::new(value),
_ => Err(Error::range()),
}
}
}
impl TryFrom<isize> for BindIndex {
type Error = Error<()>;
fn try_from(value: isize) -> Result<Self, ()> {
match c_int::try_from(value) {
Ok(value) if value > 0 => Self::new(value),
_ => Err(Error::range()),
}
}
}
impl TryFrom<u32> for BindIndex {
type Error = Error<()>;
fn try_from(value: u32) -> Result<Self, ()> {
match c_int::try_from(value) {
Ok(value) if value > 0 => Self::new(value),
_ => Err(Error::range()),
}
}
}
impl TryFrom<u64> for BindIndex {
type Error = Error<()>;
fn try_from(value: u64) -> Result<Self, ()> {
match c_int::try_from(value) {
Ok(value) if value > 0 => Self::new(value),
_ => Err(Error::range()),
}
}
}
impl TryFrom<usize> for BindIndex {
type Error = Error<()>;
fn try_from(value: usize) -> Result<Self, ()> {
match c_int::try_from(value) {
Ok(value) if value > 0 => Self::new(value),
_ => Err(Error::range()),
}
}
}
#[cfg(feature = "lang-step-trait")]
impl core::iter::Step for BindIndex {
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
if start.0.get() <= end.0.get() {
let steps = (end.0.get() - start.0.get()) as usize;
(steps, Some(steps))
} else {
(0, None)
}
}
fn forward_checked(start: Self, count: usize) -> Option<Self> {
let count = c_int::try_from(count).ok()?;
let new_value = start.0.get().checked_add(count)?;
NonZero::new(new_value).map(Self)
}
fn backward_checked(start: Self, count: usize) -> Option<Self> {
let count = c_int::try_from(count).ok()?;
let new_value = start.0.get().checked_sub(count)?;
NonZero::new(new_value).map(Self)
}
}
pub struct BindIndexes {
current: BindIndex,
}
impl BindIndexes {
const fn new(initial: BindIndex) -> Self {
Self { current: initial }
}
}
impl Iterator for BindIndexes {
type Item = BindIndex;
fn next(&mut self) -> Option<Self::Item> {
let current = self.current;
self.current = self.current.next();
Some(current)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::MAX, None)
}
}