#![no_std]
#![doc = include_str!("../README.md")]
extern crate alloc;
pub mod iter;
pub mod from_str;
pub mod convert;
use core::{
char::*,
cmp::Ordering,
fmt::{self, Debug, Display},
num::NonZeroU32,
};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct NonZeroChar(NonZeroU32);
impl Debug for NonZeroChar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.get(), f)
}
}
impl Display for NonZeroChar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&self.get(), f)
}
}
impl PartialEq<char> for NonZeroChar {
fn eq(&self, other: &char) -> bool {
self.get() == *other
}
}
impl PartialEq<NonZeroChar> for char {
fn eq(&self, other: &NonZeroChar) -> bool {
*self == other.get()
}
}
impl PartialOrd<char> for NonZeroChar {
fn partial_cmp(&self, other: &char) -> Option<Ordering> {
self.get().partial_cmp(other)
}
fn lt(&self, other: &char) -> bool {
self.get().lt(other)
}
fn le(&self, other: &char) -> bool {
self.get().le(other)
}
fn gt(&self, other: &char) -> bool {
self.get().gt(other)
}
fn ge(&self, other: &char) -> bool {
self.get().ge(other)
}
}
impl PartialOrd<NonZeroChar> for char {
fn partial_cmp(&self, other: &NonZeroChar) -> Option<Ordering> {
self.partial_cmp(&other.get())
}
fn lt(&self, other: &NonZeroChar) -> bool {
self.lt(&other.get())
}
fn le(&self, other: &NonZeroChar) -> bool {
self.le(&other.get())
}
fn gt(&self, other: &NonZeroChar) -> bool {
self.gt(&other.get())
}
fn ge(&self, other: &NonZeroChar) -> bool {
self.ge(&other.get())
}
}
impl NonZeroChar {
pub const fn new(ch: char) -> Option<Self> {
match NonZeroU32::new(ch as u32) {
Some(ch) => Some(Self(ch)),
None => None,
}
}
#[track_caller]
pub const unsafe fn new_unchecked(ch: char) -> Self {
#[cfg(debug_assertions)]
debug_assert!(Self::new(ch).is_some(),
"NonZeroChar::new_unchecked() by zero");
unsafe {
Self(NonZeroU32::new_unchecked(ch as u32))
}
}
pub const fn get(self) -> char {
unsafe { char::from_u32_unchecked(self.0.get()) }
}
pub fn iter_inclusive(self, max: Self) -> iter::RangeInclusiveIter {
let iter = self.get()..=max.get();
iter::RangeInclusiveIter { iter: iter.into_iter() }
}
pub const MIN: Self = Self::new('\x01').unwrap();
pub const MAX: Self = Self::new('\u{10FFFF}').unwrap();
pub const REPLACEMENT_CHARACTER: Self = Self::new('\u{FFFD}').unwrap();
pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;
#[inline]
pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> iter::DecodeUtf16<I::IntoIter> {
iter::DecodeUtf16 { iter: char::decode_utf16(iter) }
}
pub fn as_nonzero_u32(self) -> NonZeroU32 {
self.0
}
pub fn as_u32(self) -> u32 {
self.as_nonzero_u32().get()
}
#[must_use]
#[inline]
pub const fn from_u32(i: u32) -> Option<Self> {
match char::from_u32(i) {
Some(ch) => Self::new(ch),
None => None,
}
}
#[must_use]
#[inline]
pub const unsafe fn from_u32_unchecked(i: u32) -> Self {
unsafe {
Self(NonZeroU32::new_unchecked(i))
}
}
#[must_use]
#[inline]
pub const fn from_digit(num: u32, radix: u32) -> Option<Self> {
match char::from_digit(num, radix) {
Some(ch) => {
unsafe { Some(Self::new_unchecked(ch)) }
},
None => None,
}
}
#[inline]
pub fn is_digit(self, radix: u32) -> bool {
self.get().is_digit(radix)
}
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const fn to_digit(self, radix: u32) -> Option<u32> {
self.get().to_digit(radix)
}
#[must_use = "this returns the escaped char as an iterator, \
without modifying the original"]
#[inline]
pub fn escape_unicode(self) -> EscapeUnicode {
self.get().escape_unicode()
}
#[must_use = "this returns the escaped char as an iterator, \
without modifying the original"]
#[inline]
pub fn escape_debug(self) -> EscapeDebug {
self.get().escape_debug()
}
#[must_use = "this returns the escaped char as an iterator, \
without modifying the original"]
#[inline]
pub fn escape_default(self) -> EscapeDefault {
self.get().escape_default()
}
#[inline]
#[must_use]
pub const fn len_utf8(self) -> usize {
self.get().len_utf8()
}
#[inline]
#[must_use]
pub const fn len_utf16(self) -> usize {
self.get().len_utf16()
}
#[inline]
pub const fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
self.get().encode_utf8(dst)
}
#[inline]
pub const fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
self.get().encode_utf16(dst)
}
#[must_use]
#[inline]
pub fn is_alphabetic(self) -> bool {
self.get().is_alphabetic()
}
#[must_use]
#[inline]
pub const fn is_lowercase(self) -> bool {
self.get().is_lowercase()
}
#[must_use]
#[inline]
pub const fn is_uppercase(self) -> bool {
self.get().is_uppercase()
}
#[must_use]
#[inline]
pub fn is_whitespace(self) -> bool {
self.get().is_whitespace()
}
#[must_use]
#[inline]
pub fn is_alphanumeric(self) -> bool {
self.get().is_alphanumeric()
}
#[must_use]
#[inline]
pub fn is_control(self) -> bool {
self.get().is_control()
}
#[must_use]
#[inline]
pub fn is_numeric(self) -> bool {
self.get().is_numeric()
}
#[must_use = "this returns the lowercase character as a new iterator, \
without modifying the original"]
#[inline]
pub fn to_lowercase(self) -> ToLowercase {
self.get().to_lowercase()
}
#[must_use = "this returns the uppercase character as a new iterator, \
without modifying the original"]
#[inline]
pub fn to_uppercase(self) -> ToUppercase {
self.get().to_uppercase()
}
#[must_use]
#[inline]
pub const fn is_ascii(&self) -> bool {
self.get().is_ascii()
}
#[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"]
#[inline]
pub const fn to_ascii_uppercase(&self) -> Self {
let ch = self.get().to_ascii_uppercase();
unsafe { Self::new_unchecked(ch) }
}
#[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"]
#[inline]
pub const fn to_ascii_lowercase(&self) -> Self {
let ch = self.get().to_ascii_lowercase();
unsafe { Self::new_unchecked(ch) }
}
#[inline]
pub const fn eq_ignore_ascii_case(&self, other: &char) -> bool {
self.get().eq_ignore_ascii_case(other)
}
#[inline]
pub const fn make_ascii_uppercase(&mut self) {
let mut ch = self.get();
ch.make_ascii_uppercase();
*self = unsafe { Self::new_unchecked(ch) }
}
#[inline]
pub const fn make_ascii_lowercase(&mut self) {
let mut ch = self.get();
ch.make_ascii_lowercase();
*self = unsafe { Self::new_unchecked(ch) }
}
#[must_use]
#[inline]
pub const fn is_ascii_alphabetic(&self) -> bool {
self.get().is_ascii_alphabetic()
}
#[must_use]
#[inline]
pub const fn is_ascii_uppercase(&self) -> bool {
self.get().is_ascii_uppercase()
}
#[must_use]
#[inline]
pub const fn is_ascii_lowercase(&self) -> bool {
self.get().is_ascii_lowercase()
}
#[must_use]
#[inline]
pub const fn is_ascii_alphanumeric(&self) -> bool {
self.get().is_ascii_alphanumeric()
}
#[must_use]
#[inline]
pub const fn is_ascii_digit(&self) -> bool {
self.get().is_ascii_digit()
}
#[must_use]
#[inline]
pub const fn is_ascii_hexdigit(&self) -> bool {
self.get().is_ascii_hexdigit()
}
#[must_use]
#[inline]
pub const fn is_ascii_punctuation(&self) -> bool {
self.get().is_ascii_punctuation()
}
#[must_use]
#[inline]
pub const fn is_ascii_graphic(&self) -> bool {
self.get().is_ascii_graphic()
}
#[must_use]
#[inline]
pub const fn is_ascii_whitespace(&self) -> bool {
self.get().is_ascii_whitespace()
}
#[must_use]
#[inline]
pub const fn is_ascii_control(&self) -> bool {
self.get().is_ascii_control()
}
}
#[test]
fn test_control_upper() {
let _ = (
NonZeroChar::MIN,
NonZeroChar::MAX,
NonZeroChar::REPLACEMENT_CHARACTER,
NonZeroChar::UNICODE_VERSION,
);
assert_eq!('\x01'.to_ascii_uppercase(), '\x01');
}
#[test]
fn test_npo() {
assert_eq!(size_of::<Option<NonZeroChar>>(), size_of::<NonZeroChar>());
}