Skip to main content

token_dict/
lib.rs

1impl<I:IntoIterator> From<I> for UTF8CharIter<I::IntoIter> where I::Item:Val<u8>{
2	fn from(value:I)->Self{
3		Self{inner:value.into_iter()}
4	}
5}
6impl<I:Iterator> Iterator for UTF8CharIter<I> where I::Item:Val<u8>{
7	fn next(&mut self)->Option<Result<char,[u8;4]>>{
8		let inner=&mut self.inner;
9											// find expected number of bytes for this character
10		let firstbyte=inner.next()?.val();
11		let mut bytes=[firstbyte,0,0,0];
12		let (charlen,minpoint,value)=if firstbyte&0b10000000==0b00000000{(1,0,firstbyte)}
13		                        else if firstbyte&0b11000000==0b10000000{return Some(Err(bytes))}
14		                        else if firstbyte&0b11100000==0b11000000{(2,   0x80,firstbyte&0b00011111)}
15		                        else if firstbyte&0b11110000==0b11100000{(3,  0x800,firstbyte&0b00001111)}
16		                        else if firstbyte&0b11111000==0b11110000{(4,0x10000,firstbyte&0b00000111)}
17		else{return Some(Err(bytes))};
18		let mut value=value as u32;
19											// accumulate code point value
20		for n in 1..charlen{
21			let nextbyte=if let Some(b)=inner.next(){b.val()}else{return Some(Err(bytes))};
22			bytes[n]=nextbyte;
23			if nextbyte&0b11000000==0b10000000{value=(value<<6)+((nextbyte&0b00111111) as u32)}else{return Some(Err(bytes))}
24		}									// reject overlong encodings
25		if minpoint>value{return Some(Err(bytes))}
26											// convert to char if the code point value is a valid character
27		char::from_u32(value).map(Ok).or(Some(Err(bytes)))
28	}
29	fn size_hint(&self)->(usize,Option<usize>){
30		let (lowerbytes,upperbytes)=self.inner.size_hint();
31
32		(lowerbytes/4,upperbytes)
33	}
34	type Item=Result<char,[u8;4]>;
35}
36impl<I:Iterator> UTF8CharIter<I> where I::Item:Val<u8>{
37	/// converts into the inner value
38	pub fn into_inner(self)->I{self.inner}
39}
40impl<T:Copy> Val<T> for &T{
41	fn val(self)->T{*self}
42}
43impl<T> Val<T> for T{
44	fn val(self)->T{self}
45}
46#[cfg(test)]
47mod tests{
48	#[test]
49	fn utf8_test_1(){
50		let iter=UTF8CharIter::from("correct string".as_bytes());
51		let c:String=iter.filter_map(|c|c.ok()).collect();
52		assert_eq!(c,"correct string");
53		let iter=UTF8CharIter::from("incorrect string".bytes().chain([255,255]).chain(" incorrectness removed".bytes()));
54		let c:String=iter.filter_map(|c|c.ok()).collect();
55		assert_eq!(c,"incorrect string incorrectness removed");
56
57		let iter=UTF8CharIter::from("正しくない文字列".bytes().chain([128,255,0x20,255,0b10000000]).chain(" 不正確さは削除された".bytes()));
58		let c:String=iter.filter_map(|c|c.ok()).collect();
59		assert_eq!(c,"正しくない文字列  不正確さは削除された");
60	}
61	#[test]
62	fn test_utf8_char_iter_valid() {
63		// Unicode character '€' (euro sign)
64		let bytes = vec![0xE2u8, 0x82u8, 0xACu8];
65		let mut iter: UTF8CharIter<_> = bytes.into_iter().into();
66		match iter.next() {
67			Some(Ok(c)) => assert_eq!(c, '€'),
68			other => panic!("Expected Ok('€'), got {:?}", other),
69		}
70		// No more characters
71		assert!(iter.next().is_none());
72	}
73	#[test]
74	fn test_utf8_char_iter_error() {
75		// Invalid UTF-8 start byte
76		let bytes = vec![0xFFu8];
77		let mut iter: UTF8CharIter<_> = bytes.into_iter().into();
78		match iter.next() {
79			Some(Err(buf)) => assert_eq!(buf[0], 0xFF),
80			other => panic!("Expected Err with first byte 0xFF, got {:?}", other),
81		}
82	}
83	use super::*;
84}
85/// module for token dictionary
86pub mod dict;
87/// module for Token type
88pub mod token;
89#[derive(Clone,Debug)]
90/// iterator for live converting utf8 to chars, returning errors for all bytes that aren't part of a valid character. useful for lazily detokenizing into a string
91pub struct UTF8CharIter<I:Iterator> where I::Item:Val<u8>{inner:I}
92/// trait for unifying primitives and their references
93pub trait Val<T>{
94	/// gets the value
95	fn val(self)->T;
96}
97pub use {dict::TokenDict,token::Token};