U+ 1.0.0 master
authorChris Morgan <me@chrismorgan.info>
committerChris Morgan <me@chrismorgan.info>
.gitignore [new file with mode: 0644]
CHANGELOG.md [new file with mode: 0644]
COPYING [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
KNOWN_ISSUES.md [new file with mode: 0644]
README.md [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..96ef6c0
--- /dev/null
@@ -0,0 +1,2 @@
+/target
+Cargo.lock
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..73e25ee
--- /dev/null
@@ -0,0 +1,18 @@
+# Changelog
+
+## 1.0.0 (2022-04-01)
+
+Like a breath of fresh air wafting down from above,
+Bringing enlightenment to the masses,
+This is the initial release,
+Perfect in every way.
+
+(See also KNOWN_ISSUES.md.)
+
+# Afterword
+
+Just because something is a joke doesn’t mean it shouldn’t get a changelog.
+Think of the poor code’s feelings!
+“Woe is me,” it might otherwise say:
+“for I was created by one so cruel that he set me
+adrift in this world not knowing my heritage!”
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..b34fc67
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,24 @@
+© 2022 Chris Morgan (do not hold it against me)
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the “Software”), to appreciate
+the author’s refined sense of humour, for up to but not
+exceeding five (5) minutes’ duration.
+
+Any subsequent merriment may only be had upon expressing
+this amusement to the author in word or currency.
+
+All other rights are reserved. You are not given leave to
+actually use whatever this is. Look, I’d sell you a license
+to use it for a thousand Australian dollars, but I must
+confess that this isn’t my best code. You could hire me to
+do better if you like: https://chrismorgan.info/hire-me/
+
+THE SOFTWARE IS WARRANTED UNMERCHANTABLE, AND UNFIT FOR
+ANY PURPOSE SAVE HUMOUR, AND EVEN THAT MAY BE DEBATED.
+IF YOU USE THIS SOFTWARE, YOU DESERVE WHAT YOU GET;
+I MAY BE LIABLE TO LAUGH IF I HEAR, BUT THAT IS THE
+FULL EXTENT OF MY LIABILITY. DAMAGES ARE ON YOU.
+
+(Apologies to the MIT license, whence I lifted the most.)
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..ba8ce45
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "u-plus"
+version = "1.0.0"
+authors = ["Chris Morgan <rust@chrismorgan.info>"]
+edition = "2021"
+description = "Pretty Unicode code point literals: U+12345 instead of '\\u{12345}'"
+repository = "https://git.chrismorgan.info/u-plus"
+keywords = ["joke"]
+categories = ["rust-patterns", "no-std"]
+license-file = "COPYING"
diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md
new file mode 100644 (file)
index 0000000..5317615
--- /dev/null
@@ -0,0 +1,35 @@
+Known issues that probably won’t ever be fixed (and hopefully *can’t* ever be fixed):
+
+- Unicode scalar values whose hexadecimal representations contain a non-decimal
+  character (such as U+1F622) cannot use this representation (except as noted below).
+
+  (I thought I might have to mention that surrogates like U+DEAD can’t be
+  represented because of using `char`, but this rule already covers surrogates,
+  as they all start with D and so already couldn’t be expressed.
+  I’m sticking with calling this code point literals rather than
+  scalar value literals, and you probably can’t stop me.)
+
+- Sequences ending in F32 or F64 (e.g. U+0F32) but containing no other
+  non-decimal characters work, but the F has to be lowercase (e.g. `U+0f32`).
+
+- If you write the number after `U+` in a format other than decimal,
+  you will be punished with incorrect answers (other than for zero).
+  I mean, really, what did you *expect*, writing a monstrosity like `U+0x1F92E`?
+
+Known issues that could conceivably become fixable at some future point (but probably not):
+
+- rustfmt will uglify the code, turning `U+1234` into `U + 1234` and possibly
+  even inserting a line break. Tch. Such poor taste.
+
+Known issues that will probably become fixable in the future:
+
+- Depends on nightly rustc for various const stuff.
+  (You do want your Unicode literals checked at compile time, right?)
+
+- Doesn’t explain the error very well.
+
+Other limitations:
+
+- This only works in stead of `char` literals; for string literals,
+  you *could* use things like the `const_format` crate if you really want to,
+  like `concatcp!("U+1234 = ", U+1234)`.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..7b48d32
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# U+: pretty Unicode code point literals
+
+I was reading <https://uncyclopedia.com/wiki/Rust_(programming_language)>
+for some reason, and read `let U = 0; U = U + 1;`.
+
+Suddenly my mind was awhirl with a Concept. I implemented it at once.
+
+## The problem
+
+Unicode expresses its code points in syntax like U+1234 (full range U+0000–U+10FFFF).
+
+But then when you want to transfer it to a programming language,
+you have to learn another syntax. Will it be `\u1234`, `\u{1234}`,
+`\x1E\x88\xB4`, `\341\210\264`, something else?
+
+And then astral plane characters make it even worse:
+`\U0001F631`, `\u{1F631}`, `\xF0\x9F\x98\xB1`, `\uD83D\uDE31`
+(with all the associated pain the abomination UTF-16 entails,
+especially that your char type may simply not be able to represent this),
+something else?
+
+And so here is this crate that lets you use the True Unicode Syntax:
+
+```rust
+use u_plus::U;
+
+assert_eq!(U+1234, '\u{1234}');
+```
+
+So forget about `\u{…}` syntax!
+
+(Caution: there are some limitations with this approach, see KNOWN_ISSUES.md for details.)
+
+> “All things are lawful for me,” but not all things are profitable.
+> “All things are lawful for me,” but not all things build up.
+>
+> — Paul the Apostle, *1 Corinthians 10:23*
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..e853663
--- /dev/null
@@ -0,0 +1,90 @@
+// 99 characters, I guess I can’t add any more feature flags. Just as well I have all those I need.
+#![feature(const_trait_impl, const_char_convert, const_option, const_fn_floating_point_arithmetic)]
+#![no_std]
+// What do you want *docs* for!? (But I will begrudgingly allow doctests to run.)
+#![cfg(any(not(doc), doctest))]
+
+use core::ops::Add;
+
+pub struct U;
+
+impl const Add<u32> for U {
+    type Output = char;
+
+    fn add(self, n: u32) -> char {
+        char::from_u32(
+            n % 10 +
+            (n / 10) % 10 * 0x10 +
+            (n / 100) % 10 * 0x100 +
+            (n / 1000) % 10 * 0x1000 +
+            (n / 10000) % 10 * 0x10000 +
+            (n / 100000) % 10 * 0x100000
+        ).expect("I expected better of you. Depart, and reflect upon your transgressions.")
+    }
+}
+
+impl const Add<f32> for U {
+    type Output = char;
+
+    fn add(self, f: f32) -> char {
+        let n = f as u32;
+        if f != (n as f32) {
+            panic!("Begone, fractionaliser of U+ literals!");
+        }
+        char::from_u32(
+            0xf32 +
+            n % 10 * 0x1000 +
+            (n / 10) % 10 * 0x10000 +
+            (n / 100) % 10 * 0x100000
+        ).expect("Will you never be better?")
+    }
+}
+
+impl const Add<f64> for U {
+    type Output = char;
+
+    fn add(self, f: f64) -> char {
+        let n = f as u32;
+        if f != (n as f64) {
+            panic!("Get ye hence, fracticious one!");
+        }
+        char::from_u32(
+            0xf64 +
+            n % 10 * 0x1000 +
+            (n / 10) % 10 * 0x10000 +
+            (n / 100) % 10 * 0x100000
+        ).expect("I am exceedingly wrothful to youwards.")
+    }
+}
+
+#[test]
+fn success() {
+    assert_eq!(U+0000, '\u{0}');
+    assert_eq!(U+1234, '\u{1234}');
+    assert_eq!(U+2f64, '\u{2f64}');
+    assert_eq!(U+102f64, '\u{102f64}');
+    assert_eq!(U+104f32, '\u{104f32}');
+    // Evaluated at const time!
+    const MAX: char = U+109999;
+    assert_eq!(MAX, '\u{109999}');
+}
+
+/// ```rust
+/// #![feature(const_trait_impl)]  // Not sure quite why this is needed, but meh.
+/// use u_plus::U;
+/// const HAPPINESS: char = U+2323;
+/// ```
+///
+/// ```rust,compile_fail
+/// #![feature(const_trait_impl)]
+/// use u_plus::U;
+/// const MISERY: char = U+119999;
+/// ```
+///
+/// ```rust,compile_fail
+/// #![feature(const_trait_impl)]
+/// use u_plus::U;
+/// const SORROW: char = U+1F622;
+/// ```
+#[cfg(doctest)]
+const _: () = ();