5 releases
0.2.0 | Jul 9, 2023 |
---|---|
0.1.5 | Jul 8, 2023 |
0.1.4 | Jul 6, 2023 |
0.1.3 | Jul 4, 2023 |
0.1.2 | Jul 4, 2023 |
#1543 in Encoding
160KB
2.5K
SLoC
cj_ascii
A library for working with ASCII strings in Rust
AsciiString is a String like struct for working with ASCII and Extended ASCII characters.
Because it accepts Extended ASCII, all u8 values are accepted.
Key features:
* TryFrom traits have been implemented for string types.
* push/pop push_front/pop_front have been implemented for both char and u8.
* u8 (ascii ordinals) can be accessed by index and updated directly.
* Concatenation of char, u8, &str and AsciiString is supported (will panic if char/string is not valid ASCII).
* Iterators for both u8 and char.
* raw bytes via as_bytes() and as_bytes_mut(), where the bytes are guaranteed to be valid ASCII (one byte = one char).
* stream support via AsciiStreamReader and AsciiStreamWriter (included in this crate).
* async stream support via AsciiStreamReaderAsync and AsciiStreamWriterAsync (included in this crate).
samples
Basic example
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::try_from("This is a test").unwrap();
let mut astring2 = AsciiString::with_capacity(14);
astring2 += "This";
astring2 += " is";
astring2 += " a";
astring2 += " test";
assert_eq!(astring, astring2);
}
Mix of char, u8, &str and AsciiString concatenation.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += 'A';
astring += 66;
astring += "C";
astring += "DEF";
let astring2 = AsciiString::from(&astring);
astring += astring2;
assert_eq!(&astring.to_string(), "ABCDEFABCDEF");
}
Indexing
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += 'A';
astring += 66;
astring += "C";
astring += "DEF";
assert_eq!(astring[0], 'A'.ascii_ord_unchecked());
assert_eq!(astring[1].to_ascii_char(), 'B');
assert_eq!(astring[2], 67);
assert_eq!(astring[3], 68);
assert_eq!(astring[4], 69);
assert_eq!(astring[5], 70);
}
Indexing Mut
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += "ABCDEF";
astring[0] = 71;
astring[1] = 'H'.ascii_ord_unchecked();
astring[2] = 73;
astring[3] = 74;
astring[4] = 75;
astring[5] = 76;
assert_eq!(astring[0], 'G'.ascii_ord_unchecked());
assert_eq!(astring.to_string(), "GHIJKL");
}
Iter
- use iter() to iterate over the raw bytes.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += "ABCDEF";
let mut iter = astring.iter();
assert_eq!(iter.next(), Some(&65));
assert_eq!(iter.next(), Some(&66));
assert_eq!(iter.next(), Some(&67));
assert_eq!(iter.next(), Some(&68));
assert_eq!(iter.next(), Some(&69));
assert_eq!(iter.next(), Some(&70));
assert_eq!(iter.next(), None);
// or
let mut iter = astring.iter();
assert_eq!(iter.next(), Some(&'A'.ascii_ord_unchecked()));
assert_eq!(iter.next(), Some(&'B'.ascii_ord_unchecked()));
assert_eq!(iter.next(), Some(&'C'.ascii_ord_unchecked()));
assert_eq!(iter.next(), Some(&'D'.ascii_ord_unchecked()));
assert_eq!(iter.next(), Some(&'E'.ascii_ord_unchecked()));
assert_eq!(iter.next(), Some(&'F'.ascii_ord_unchecked()));
assert_eq!(iter.next(), None);
}
Iter Mut
- use iter_mut() to iterate over and modify the raw bytes.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += "ABCDEF";
let mut iter = astring.iter_mut();
for c in iter {
*c = *c + 1;
}
assert_eq!(astring.to_string(), "BCDEFG");
}
Iter Ascii
- use iter_ascii() to iterate as chars.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring += "ABCDEF";
let mut iter = astring.iter_ascii();
assert_eq!(iter.next(), Some('A'));
assert_eq!(iter.next(), Some('B'));
assert_eq!(iter.next(), Some('C'));
assert_eq!(iter.next(), Some('D'));
assert_eq!(iter.next(), Some('E'));
assert_eq!(iter.next(), Some('F'));
assert_eq!(iter.next(), None);
}
Iter AsciiGroup
- AsciiGroup is an enum that represents the different categories of ASCII characters.
- PrintableCtrl - ASCII characters that are printable control characters.
- NonPrintableCtrl - ASCII characters that are non-printable control characters.
- Printable - ASCII characters that are printable (space through tilda).
- Extended - ASCII characters in the extended ascii range (ordinal 128 through 255).
fn main() {
use cj_ascii::prelude::*;
let astring = AsciiString::try_from("Hello World!").unwrap();
for x in astring.iter_ascii_group() {
match x {
AsciiGroup::PrintableCtrl(_) => println!("PrintableCtrl: {}", x.as_char()),
AsciiGroup::Printable(_) => println!("PrintableAscii: {}", x.as_char()),
AsciiGroup::NonPrintableCtrl(_) => println!("NonPrintableCtrl: {}", x.as_byte()),
AsciiGroup::Extended(_) => println!("Extended: {}", x.as_byte()),
}
}
}
Push (char or u8)
- u8 values are pushed as is and will never fail.
- char values will panic if they are not ASCII.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring.push('A');
astring.push(66);
astring.push('C');
astring.push('D');
assert_eq!(astring.to_string(), "ABCD");
astring.push_front('Z');
astring.push_front(89);
astring.push_front('X');
assert_eq!(astring.to_string(), "XYZABCD");
}
Try Push (char or u8)
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring.try_push('A').unwrap();
astring.try_push(66).unwrap();
astring.try_push('C').unwrap();
astring.try_push('D').unwrap();
assert!(astring.try_push('€').is_err());
assert_eq!(astring.to_string(), "ABCD");
let mut astring = AsciiString::new();
astring.try_push_front('A').unwrap();
astring.try_push_front(66).unwrap();
astring.try_push_front('C').unwrap();
astring.try_push_front('D').unwrap();
assert!(astring.try_push_front('€').is_err());
assert_eq!(astring.to_string(), "DCBA");
}
Push str
- use push_str if you know the string only contains ascii.
- push_str will panic if the string contains non-ascii characters.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring.push_str("ABC");
astring.push_str("DEF");
assert_eq!(astring.to_string(), "ABCDEF");
}
Push str Lossy
- push_str_lossy will replace non-ascii characters with a space.
fn main() {
use cj_ascii::prelude::*;
let mut astring = AsciiString::new();
astring.push_str_lossy("ABCD");
astring.push_str_lossy("€");
assert_eq!(astring.to_string(), "ABCD ");
}
Invalid Ascii
- try_from will return an error if the string contains non-ascii characters.
fn main() {
use cj_ascii::prelude::*;
let string = "ABC€";
let result = AsciiString::try_from(string);
assert!(result.is_err());
}
Streams
- reader
fn main() {
use cj_ascii::prelude::*;
use std::io::Cursor;
let mut reader = AsciiStreamReader::new(
Cursor::new(
[84, 104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116, 32, 49, 10, 84,
104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116, 32, 50, 13, 10, 84,
104, 105, 115, 32, 105, 115, 32, 116, 101, 115, 116, 32, 51]
)
);
let mut astring = AsciiString::new();
while reader.read_line(&mut astring).is_success() {
println!("{}", astring);
}
}
- writer
fn main() {
use cj_ascii::prelude::*;
let mut writer = AsciiStreamWriter::new(Vec::new());
let mut astring = AsciiString::new();
astring += "The beginning.";
writer.write_line(&astring).unwrap();
astring.clear();
astring += "The middle.";
writer.write_line(&astring).unwrap();
astring.clear();
astring += "The end.";
writer.write(&astring).unwrap();
let result = writer.flush();
assert!(result.is_ok());
let vec = writer.into_inner().unwrap();
assert_eq!(vec,
[84, 104, 101, 32, 98, 101, 103, 105, 110, 110, 105, 110, 103,
46, 10, 84, 104, 101, 32, 109, 105, 100, 100, 108, 101, 46,
10, 84, 104, 101, 32, 101, 110, 100, 46]
);
let result = AsciiString::from(vec);
assert_eq!(result.to_string(),"The beginning.\nThe middle.\nThe end.");
}
Async Streams
- reader
async fn read_example() {
use cj_ascii::prelude::*;
use futures::io::Cursor;
let mut stream = AsciiStreamReaderAsync::new(Cursor::new(b"abc\r\ndef\r\nghi"));
let mut buf = AsciiString::new();
while stream.read_line(&mut buf).await.is_success() {
println!("{}", buf);
}
}
// tokio example
async fn read_example_tokio() {
use cj_ascii::prelude::*;
use tokio_util::compat::*;
let file_name = "C:/Temp/EnglishWords/words_ansi.txt";
let file = tokio::fs::File::open(file_name).await.unwrap();
let mut stream = AsciiStreamReaderAsync::new(file.compat());
let mut line = AsciiString::new();
while stream.read_line(&mut line).await.is_success() {
println!("{}", line);
}
}
- writer
async fn write_example() {
use cj_ascii::prelude::*;
use futures::io::Cursor;
let mut stream = AsciiStreamWriterAsync::new(Cursor::new(Vec::new()));
let mut buf = AsciiString::new();
buf += "abc";
stream.write_line(&buf).await.unwrap();
buf.clear();
buf += "def";
stream.write_line(&buf).await.unwrap();
buf.clear();
buf += "ghi";
stream.write(&buf).await.unwrap();
stream.flush().await.unwrap();
let result = stream.into_inner();
assert_eq!(result.into_inner(), [97, 98, 99, 10, 100, 101, 102, 10, 103, 104, 105]);
}
// tokio example
async fn write_example_tokio() {
use cj_ascii::prelude::*;
use tokio_util::compat::*;
let file_name = "C:/Temp/Test/words_ansi_out.txt";
let file = tokio::fs::File::create(file_name).await.unwrap();
let mut stream = AsciiStreamWriterAsync::new(file.compat());
let mut line = AsciiString::new();
line += "abc";
stream.write_line(&line).await.unwrap();
line.clear();
line += "def";
stream.write_line(&line).await.unwrap();
line.clear();
line += "ghi";
stream.write(&line).await.unwrap();
stream.flush().await.unwrap();
}
Dependencies
~0–295KB