Skip to content

Commit

Permalink
Better No Std (#6)
Browse files Browse the repository at this point in the history
* Found remaining std features in core and removed features

* Updated README

* Added derive macros to iterator traits

* Added clippy pedantic and fixed the resulting errors
  • Loading branch information
Teh-Bobo authored Sep 10, 2022
1 parent fc75e4c commit aa8eb72
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 44 deletions.
6 changes: 1 addition & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,4 @@ authors = ["Carl Raffaele"]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/Teh-Bobo/unicode-title-case"
description = "A crate to add Unicode titlecase options to chars and strings"

[features]
default = ["std"]
std = []
description = "A crate to add Unicode titlecase options to chars and strings"
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ Add this to your `Cargo.toml`:
unicode_titlecase = "1.1.0"
```

## Features

This crate is no_std capable. ```std``` is used for
```std::Display``` on the iterators, allowing the usage of ```to_string()```.

## Usage

### Chars
Expand Down
8 changes: 4 additions & 4 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{env, fs};
use std::collections::BTreeMap;
use std::path::Path;
use std::{env, fs};

/// This takes the Unicode files found in resources/ and converts them into the titlecase cable
/// found in casing.rs.
Expand All @@ -9,7 +9,7 @@ pub fn main() {
println!("cargo:rerun-if-changed=src/");
let out_dir = env::var_os("OUT_DIR").unwrap();
let in_path = Path::new(&env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("resources");
let sc_path = in_path.clone().join("SpecialCasing.txt");
let sc_path = in_path.join("SpecialCasing.txt");
let base_path = in_path.join("UnicodeData.txt");
let dest_path = Path::new(&out_dir).join("casing.rs");

Expand All @@ -24,7 +24,7 @@ pub fn main() {
let code_point = l.next().unwrap();
let tcs = l.next().unwrap();
let tccp: Vec<&str> = tcs.split_ascii_whitespace().collect();
if let Some(tccp0) = tccp.get(0).filter(|&&tccp0| code_point != tccp0) {
if let Some(tccp0) = tccp.first().filter(|&&tccp0| code_point != tccp0) {
let cp = char::from_u32(u32::from_str_radix(code_point, 16).unwrap()).unwrap();
let tccp1 = tccp.get(1).unwrap_or(&"0");
let tccp2 = tccp.get(2).unwrap_or(&"0");
Expand All @@ -37,7 +37,7 @@ pub fn main() {
});
let base_file = fs::read_to_string(base_path).unwrap();
base_file.lines().for_each(|line| {
let mut l = line.split(";");
let mut l = line.split(';');
let cp = l.next().unwrap();
if let Some(last_cp) = l.last().filter(|&last| !last.is_empty() && cp != last) {
let cp = char::from_u32(u32::from_str_radix(cp, 16).unwrap()).unwrap();
Expand Down
61 changes: 31 additions & 30 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@
//! on [char] and [str] that adds title case handling methods. These methods are very similar to how
//! the std library currently handles uppercase and lowercase.
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![deny(rustdoc::missing_doc_code_examples)]
#![deny(unsafe_code)]
#![warn(clippy::pedantic)]

extern crate alloc;

use alloc::string::String;
use core::fmt::{Debug, Formatter, Write};
use core::fmt::{Debug, Display, Formatter, Result, Write};
use core::iter::FusedIterator;

include!(concat!(env!("OUT_DIR"), "/casing.rs"));

#[allow(clippy::doc_link_with_quotes)]
/// Accepts a char and returns the Unicode Title Case for that character as a 3 char array.
///
/// # Examples
Expand All @@ -40,7 +42,8 @@ include!(concat!(env!("OUT_DIR"), "/casing.rs"));
/// ```
/// # Locale
/// This function is not locale specific. Unicode special casing has rules for tr and az that
/// this function does not take into account. For tr and az locales use [to_titlecase_tr_or_az]
/// this function does not take into account. For tr and az locales use [`to_titlecase_tr_or_az`]
#[must_use]
pub fn to_titlecase(c: char) -> [char; 3] {
if let Ok(index) = TITLECASE_TABLE.binary_search_by(|&(key, _)| key.cmp(&c)) {
TITLECASE_TABLE[index].1
Expand All @@ -49,6 +52,7 @@ pub fn to_titlecase(c: char) -> [char; 3] {
}
}

#[allow(clippy::doc_link_with_quotes)]
/// Accepts a char and returns the Unicode Title Case for that character as a 3 char array.
///
/// # Examples
Expand All @@ -74,7 +78,8 @@ pub fn to_titlecase(c: char) -> [char; 3] {
/// ```
/// # Locale
/// This function is specific to the tr and az locales. It returns different results for certain
/// chars. To use locale agnostic version see [to_titlecase].
/// chars. To use locale agnostic version see [`to_titlecase`].
#[must_use]
pub fn to_titlecase_tr_or_az(c: char) -> [char; 3] {
if c == '\u{0069}' {
['\u{0130}', '\0', '\0']
Expand All @@ -83,10 +88,10 @@ pub fn to_titlecase_tr_or_az(c: char) -> [char; 3] {
}
}

/// This trait adds title case methods to [char]. They function the same as the std library's
/// [char::to_lowercase] and [char::to_uppercase] using a custom [ToTitleCase] iterator.
/// This trait adds title case methods to [`char`]. They function the same as the std library's
/// [`char::to_lowercase`] and [`char::to_uppercase`] using a custom [`ToTitleCase`] iterator.
pub trait TitleCase {
/// Wraps [to_titlecase] in an iterator. The iterator will yield at most 3 chars.
/// Wraps [`to_titlecase`] in an iterator. The iterator will yield at most 3 chars.
///
/// # Examples
/// If the character is already titlecase then it will return itself
Expand All @@ -111,10 +116,10 @@ pub trait TitleCase {
/// ```
/// # Locale
/// This function is not locale specific. Unicode special casing has rules for tr and az that
/// this function does not take into account. For tr and az locales use [TitleCase::to_titlecase_tr_or_az]
/// this function does not take into account. For tr and az locales use [`TitleCase::to_titlecase_tr_or_az`]
fn to_titlecase(self) -> ToTitleCase;

/// Wraps [to_titlecase_tr_or_az] in an iterator. The iterator will yield at most 3 chars.
/// Wraps [`to_titlecase_tr_or_az`] in an iterator. The iterator will yield at most 3 chars.
///
/// # Examples
/// If the character is already titlecase then it will return itself
Expand All @@ -140,7 +145,7 @@ pub trait TitleCase {
///
/// # Locale
/// This function is specific to the tr and az locales. It returns different results for certain
/// chars. To use locale agnostic version see [TitleCase::to_titlecase].
/// chars. To use locale agnostic version see [`TitleCase::to_titlecase`].
fn to_titlecase_tr_or_az(self) -> ToTitleCase;

/// Returns true if the given character is a titlecase character. This function works for all locales
Expand Down Expand Up @@ -203,7 +208,7 @@ pub trait StrTitleCase {
/// ```
/// # Locale
/// This function is not locale specific. Unicode special casing has rules for tr and az that
/// this function does not take into account. For tr and az locales use [StrTitleCase::to_titlecase_tr_or_az]
/// this function does not take into account. For tr and az locales use [`StrTitleCase::to_titlecase_tr_or_az`]
fn to_titlecase(&self) -> String;
/// Titlecases the first char of a string, lowercases the rest of the string, and returns a copy.
///
Expand All @@ -230,25 +235,25 @@ pub trait StrTitleCase {
/// ```
/// # Locale
/// This function is not locale specific. Unicode special casing has rules for tr and az that
/// this function does not take into account. For tr and az locales use [StrTitleCase::to_titlecase_tr_or_az_lower_rest]
/// this function does not take into account. For tr and az locales use [`StrTitleCase::to_titlecase_tr_or_az_lower_rest`]
fn to_titlecase_lower_rest(&self) -> String;
/// This functions the same way as [StrTitleCase::to_titlecase] except that it uses the TR/AZ
/// This functions the same way as [`StrTitleCase::to_titlecase`] except that it uses the TR/AZ
/// locales. This has one major change:
/// ```
/// use unicode_titlecase::StrTitleCase;
/// assert_eq!("iIi".to_titlecase_tr_or_az(), "İIi")
/// ```
///
/// For the locale agnostic version use [StrTitleCase::to_titlecase].
/// For the locale agnostic version use [`StrTitleCase::to_titlecase`].
fn to_titlecase_tr_or_az(&self) -> String;
/// This functions the same way as [StrTitleCase::to_titlecase_lower_rest] except that it uses
/// This functions the same way as [`StrTitleCase::to_titlecase_lower_rest`] except that it uses
/// the TR/AZ locales. This has one major change:
/// ```
/// use unicode_titlecase::StrTitleCase;
/// assert_eq!("iIi".to_titlecase_tr_or_az_lower_rest(), "İii")
/// ```
///
/// For the locale agnostic version use [StrTitleCase::to_titlecase_lower_rest].
/// For the locale agnostic version use [`StrTitleCase::to_titlecase_lower_rest`].
fn to_titlecase_tr_or_az_lower_rest(&self) -> String;

/// Tests if the first char of this string is titlecase. This is locale agnostic and returns the
Expand Down Expand Up @@ -325,24 +330,22 @@ impl StrTitleCase for str {
self.chars()
.next()
.as_ref()
.map(TitleCase::is_titlecase)
.unwrap_or(false)
.map_or(false, TitleCase::is_titlecase)
}

fn starts_titlecase_rest_lower(&self) -> bool {
let mut iter = self.chars();
iter.next()
.as_ref()
.map(TitleCase::is_titlecase)
.unwrap_or(false)
.map_or(false, TitleCase::is_titlecase)
&& iter.all(char::is_lowercase)
}
}

/// An iterator over a titlecase mapped char.
///
/// Copied from the std library's [core::char::ToLowercase] and [core::char::ToUppercase].
#[derive(Debug, Clone)]
/// Copied from the std library's [`core::char::ToLowercase`] and [`core::char::ToUppercase`].
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct ToTitleCase(CaseMappingIter);

impl Iterator for ToTitleCase {
Expand All @@ -365,15 +368,14 @@ impl FusedIterator for ToTitleCase {}

impl ExactSizeIterator for ToTitleCase {}

#[cfg(feature = "std")]
impl std::fmt::Display for ToTitleCase {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
impl Display for ToTitleCase {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
core::fmt::Display::fmt(&self.0, f)
}
}

// Copied out of the std library
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
enum CaseMappingIter {
Three(char, char, char),
Two(char, char),
Expand Down Expand Up @@ -446,9 +448,8 @@ impl DoubleEndedIterator for CaseMappingIter {
}
}

#[cfg(feature = "std")]
impl std::fmt::Display for CaseMappingIter {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
impl Display for CaseMappingIter {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match *self {
CaseMappingIter::Three(a, b, c) => {
f.write_char(a)?;
Expand Down

0 comments on commit aa8eb72

Please sign in to comment.