2 unstable releases
new 0.2.0 | Apr 18, 2025 |
---|---|
0.1.0 | Apr 5, 2025 |
#312 in Encoding
130 downloads per month
255KB
3K
SLoC
Emojfuscate: The ultimate human readable serialization format
Emojfuscate is a library that turns data into emoji. Other popular
serialization formats, like JSON and XML, serialize data using scary symbols
like {
, [
and <
. This is friendly to robots, not humans. Emojfuscate will
encode your data using emoji, i.e. pure human emotion.
As a library Emojfuscate promises to bring concrete business value to your project by virtue of it being written in Rust and being smolderingly quick.
Let's see an example.
use emojfuscate::{ConstructFromEmoji, Demojfuscate, Emojfuscate};
#[derive(Emojfuscate, ConstructFromEmoji, Clone, Debug, PartialEq)]
struct Person {
age: u8,
name: String,
is_cool: bool,
}
let original_person = Person {
age: 33,
name: "Axel".to_string(),
is_cool: true,
};
let emojified = original_person.clone().emojfuscate();
// emojified: ππ°π€©π΄π
π§Άππ·ππ΅
println!("emojified: {}", emojified.clone());
let deserialized_person = emojified.demojfuscate();
assert_eq!(deserialized_person, Ok(original_person));
Laziness
To further embrace human properties, Emojfuscate is as lazy as possible. Any iterator, whose elements can be emojfuscated, can be turned into a lazy iterator of emoji.
Any lazy stream of emoji can be converted into a lazy stream of whatever type you want as long as it can be demojfuscated. Emojfuscate can cover all your emojfuscating needs in constant memory.
use emojfuscate::{ConstructFromEmoji, Demojfuscate, Emojfuscate, ConstructFromEmojiStream};
let source = std::iter::repeat("hello"); // infinite stream of String : Iterator<Item = String>
let demojfuscated: Result<Vec<String>, emojfuscate::FromEmojiError> = source
.emojfuscate_stream() // infinite stream of emoji: Iterator<Item = char>
.demojfuscate_stream() // infinite stream of hopefully String: Iterator<Item = Result<String, FromEmojiError>>
.take(3) // finite stream of hopefully String: Iterator<Item = Result<String, FromEmojiError>>
.collect(); // Result<Vec<String>, FromEmojiError>
assert_eq!(
demojfuscated,
Ok(vec![
"hello".to_string(),
"hello".to_string(),
"hello".to_string()
])
);
How it works
Let's say we have a tuple of u8
let tuple = (1u8, 2u8, 3u8, 4u8, 5u8);
The raw bits will look like this:
1 2 3 4 5
/---^--\ /---^--\ /---^--\ /---^--\ /---^--\
00000001 00000010 00000011 00000100 00000101
Every 10 bits will be mapped to one emoji
4=π 32=π«£ 193=π 5=π
/----^----\/----^----\/----^----\/----^----\
00000001 00000010 00000011 00000100 00000101
But what if the number bits is not divisible by 10?
If we have a tuple with only two u8
let tuple = (1u8, 2u8);
Then the bits will be padded with zeros until we get an even multiple of 10
4=π 32=π«£
/----^----\/----^----\
00000001 00000010 0000
\--/
four padded zeros
The emoji with the padded zeros will be prefixed with π° to signify four padded zeros. π, π, π, π°, π, π, π, π· and π° signify that the next emoji has 1, 2, 3, 4, 5, 6, 7, 8 or 9 padded zeros respectively (though in practice it's impossible to be offset by an odd number since we're only dealing with an integer number of bytes).
So (1u8, 2u8)
will be emojfuscated into ππ°π«£.
Limitations
The derive macro for Emojfuscate and ConstructFromEmoji for enums currently rely on representing the fields as tuples. At the moment Emojfuscate and ConstructFromEmoji are only implemented for tuples up to 24 elements. So you can't derive instances for enums where any of the constructors has more than 24 fields.
Luckily we have nifty macros for making tuple instances for both Emojfuscate and ConstructFromEmoji, so if you need more fields you can easily make a PR and just call the respective macros a few extra times until your needs are satisfied.
Dependencies
~1.4β2MB
~37K SLoC