From 60bbde00b6ae727334b129bb4d3a04e8713bc059 Mon Sep 17 00:00:00 2001 From: SOFe Date: Sat, 13 Jun 2020 01:48:01 +0800 Subject: [PATCH 1/3] Rewrote this repository in Rust --- .github/workflows/ci.yml | 28 ++++++++ .gitignore | 1 + README.md | 16 ++++- justfile | 19 ++++++ riir-macro/Cargo.lock | 33 +++++++++ riir-macro/Cargo.toml | 14 ++++ riir-macro/src/lib.rs | 142 +++++++++++++++++++++++++++++++++++++++ riir-macro/test.txt | 2 + 8 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 justfile create mode 100644 riir-macro/Cargo.lock create mode 100644 riir-macro/Cargo.toml create mode 100644 riir-macro/src/lib.rs create mode 100644 riir-macro/test.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fb2b2f1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: CI +on: + - push + - pull_request +jobs: + build: + name: Rust clippy and unit tests + runs-on: ubuntu-latest + strategy: + matrix: + rustup_channel: + - stable + - beta + - nightly + dev_flag: + - "" + - "--release" + steps: + - uses: actions/checkout@v2 + - name: rustup install + run: | + rustup toolchain update --no-self-update ${{ matrix.rustup_channel }} + rustup default ${{ matrix.rustup_channel }} + - name: install just + run: cargo install just + - run: just build + - name: unit tests + run: just test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/README.md b/README.md index 500f3c2..a2ca07e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,16 @@ +// # RIIR why not Rewrite It In Rust (**RIIR**) Are you an author or contributor to a software project? -Have you ever been asked to rewrite, or consider rewriting that project in [Rust](https://www.rust-lang.org/)? +Have you ever been asked to rewrite, or consider rewriting that project in [Rust][rust-lang]? If so, you may have been a victim of the RIIR agenda that is sweeping the web. -If this has happened to you, please [report it](https://github.com/ansuz/RIIR/issues/) so that something can be done. +If this has happened to you, please [report it][issues] so that something can be done. ## FAQ @@ -18,7 +21,14 @@ No. This is a joke. ### Y U HATE RUST SO MUCH? -I don't, actually. I believe that those who spend their time asking people to rewrite their projects are probably not themselves active Rust developers, as those active devs are probably busy [writing memory-safe code](https://trac.torproject.org/projects/tor/ticket/11331). +I don't, actually. I believe that those who spend their time asking people to rewrite their projects are probably not themselves active Rust developers, as those active devs are probably busy [writing memory-safe code][memory-safe]. ### R U OFFENDING ME? ![](rust.png) + +[rust-lang]: https://www.rust-lang.org/ +[issues]: https://github.com/ansuz/RIIR/issues/ +[memory-safe]: https://trac.torproject.org/projects/tor/ticket/11331 + + diff --git a/justfile b/justfile new file mode 100644 index 0000000..8f9b623 --- /dev/null +++ b/justfile @@ -0,0 +1,19 @@ +build: clean build-macro + #!/usr/bin/env bash + LIB_PATH=$(echo -n target/debug/deps/libriir_macro-*.so) + rustc \ + --crate-name riir \ + --edition=2018 \ + README.md \ + --crate-type bin \ + --out-dir target/debug/deps \ + -L dependency=target/debug/deps \ + --extern riir_macro=$LIB_PATH +clean: + #!/usr/bin/env bash + rm target/debug/deps/libriir_macro-*.so || true +build-macro: + cd riir-macro && cargo build --target-dir=../target $( (rustc --version | grep nightly >/dev/null) && echo --features span) + +test: + cd riir-macro && cargo test --target-dir=../target $( (rustc --version | grep nightly >/dev/null) && echo --features span) diff --git a/riir-macro/Cargo.lock b/riir-macro/Cargo.lock new file mode 100644 index 0000000..c7f96f9 --- /dev/null +++ b/riir-macro/Cargo.lock @@ -0,0 +1,33 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "proc-macro2" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riir-macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/riir-macro/Cargo.toml b/riir-macro/Cargo.toml new file mode 100644 index 0000000..25ce472 --- /dev/null +++ b/riir-macro/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "riir-macro" +version = "0.1.0" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.18" +quote = "1.0.6" + +[features] +span = ["proc-macro2/span-locations"] diff --git a/riir-macro/src/lib.rs b/riir-macro/src/lib.rs new file mode 100644 index 0000000..d34d077 --- /dev/null +++ b/riir-macro/src/lib.rs @@ -0,0 +1,142 @@ +#![cfg_attr(feature = "span", feature(proc_macro_span))] + +use proc_macro2::{Delimiter, Span, TokenStream, TokenTree}; +use quote::quote; + +#[proc_macro] +pub fn print_literally(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { + let string = print_ts(ts.into()); + let ts = quote! { + fn main() { + print!(#string); + } + }; + ts.into() +} + +fn print_ts(ts: TokenStream) -> String { + let mut output = String::new(); + + #[cfg_attr(feature = "span", allow(unused_mut, unused_variables))] + let mut was_hash = false; + #[cfg_attr(not(feature = "span"), allow(unused_mut, unused_variables))] + let mut last_span: Option = None; + + for tt in ts { + #[cfg(feature = "span")] + { + if let Some(last_span) = last_span { + let end = last_span.end(); + let start = tt.span().start(); + let end_col = if start.line > end.line { + let lines = start.line - end.line; + output.extend((0..lines).map(|_| '\n')); + 0 + } else { + end.column + }; + let space_size = start.column as isize - end_col as isize; + output.extend((0..space_size).map(|_| ' ')); + } + } + #[cfg_attr(not(feature = "span"), allow(unused_assignments))] + { + last_span = Some(tt.span()); + } + match tt { + TokenTree::Ident(ident) => { + #[cfg_attr(not(feature = "span"), allow(unused_mut))] + let mut string = ident.to_string(); + #[cfg(feature = "span")] + { + fill_space(ident.span(), &mut string); + } + #[cfg(not(feature = "span"))] + { + string.push(' '); + } + output.push_str(&string); + } + TokenTree::Punct(punct) => { + let mut string = punct.as_char().to_string(); + #[cfg(feature = "span")] + { + fill_space(punct.span(), &mut string); + } + #[cfg(not(feature = "span"))] + { + use proc_macro2::Spacing; + + if punct.as_char() == '#' { + if !was_hash { + string = format!("\n{}", string); + } + was_hash = true; + } + if punct.spacing() == Spacing::Joint { + string.push(' '); + } + } + output.push_str(&string); + } + TokenTree::Literal(lit) => { + #[cfg_attr(not(feature = "span"), allow(unused_mut))] + let mut string = lit.to_string(); + #[cfg(feature = "span")] + { + fill_space(lit.span(), &mut string); + } + output.push_str(&string); + } + TokenTree::Group(group) => { + let mut string = String::new(); + let (l, r) = match group.delimiter() { + Delimiter::Parenthesis => ("(", ")"), + Delimiter::Bracket => ("[", "]"), + Delimiter::Brace => ("{", "}"), + Delimiter::None => ("", ""), + }; + string.push_str(l); + string.push_str(&print_ts(group.stream())); + string.push_str(r); + #[cfg(feature = "span")] + { + fill_space(group.span(), &mut string); + } + output.push_str(&string); + } + } + } + output +} + +#[cfg(feature = "span")] +fn fill_space(span: Span, string: &mut String) { + let start_col = if span.end().line > span.start().line { + let lines = span.end().line - span.start().line; + string.extend((0..lines).map(|_| '\n')); + -1 + } else { + (span.start().column + string.len()) as isize + }; + let space_size = span.end().column as isize - start_col; + string.extend((0..space_size).map(|_| ' ')); +} + +#[cfg(test)] +#[test] +fn test() { + use std::{fs, path::PathBuf}; + + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test.txt"); + let content = fs::read_to_string(path).unwrap(); + let actual = print_ts(content.parse().unwrap()); + #[cfg(feature = "span")] + { + assert_eq!(actual, content.trim()); + } + #[cfg(not(feature = "span"))] + { + // TODO write unit tests for non-span-sensitive code + } +} diff --git a/riir-macro/test.txt b/riir-macro/test.txt new file mode 100644 index 0000000..40edba1 --- /dev/null +++ b/riir-macro/test.txt @@ -0,0 +1,2 @@ +a bc + ## de f From 6ba577b48c7884c4d23ef5097e8d8d01bf0cd8d2 Mon Sep 17 00:00:00 2001 From: SOFe Date: Thu, 4 Mar 2021 20:26:07 +0800 Subject: [PATCH 2/3] Updated building instructions --- README.md | 16 ++++++++++++++-- justfile | 2 +- rust-toolchain | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 rust-toolchain diff --git a/README.md b/README.md index a2ca07e..cdf15d7 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,21 @@ I don't, actually. I believe that those who spend their time asking people to re ### R U OFFENDING ME? ![](rust.png) +## Building +This readme is written in Rust to further rebut arguments that Rust has low readability. +The readme can be built into an executable by running the [just][just] command: + +> just build + +Then run "just test", and this readme will be regenerated in Rust code! + +(Unfortunately, Rust does not have backticks, +so we cannot write code spans properly in this readme.) + [rust-lang]: https://www.rust-lang.org/ [issues]: https://github.com/ansuz/RIIR/issues/ [memory-safe]: https://trac.torproject.org/projects/tor/ticket/11331 +[just]: https://github.com/casey/just - +// diff --git a/justfile b/justfile index 8f9b623..0448e9d 100644 --- a/justfile +++ b/justfile @@ -6,7 +6,7 @@ build: clean build-macro --edition=2018 \ README.md \ --crate-type bin \ - --out-dir target/debug/deps \ + --out-dir target/debug \ -L dependency=target/debug/deps \ --extern riir_macro=$LIB_PATH clean: diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..bf867e0 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly From f9e02ff2bf28baac752944923c56a320cab6fa1f Mon Sep 17 00:00:00 2001 From: SOFe Date: Fri, 5 Mar 2021 16:37:14 +0800 Subject: [PATCH 3/3] Fixed formatting --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cdf15d7..060d57c 100644 --- a/README.md +++ b/README.md @@ -27,16 +27,13 @@ I don't, actually. I believe that those who spend their time asking people to re ![](rust.png) ## Building -This readme is written in Rust to further rebut arguments that Rust has low readability. -The readme can be built into an executable by running the [just][just] command: +This readme is valid Rust language. +It can be built into an executable by running the [just][just] command: -> just build + just build Then run "just test", and this readme will be regenerated in Rust code! -(Unfortunately, Rust does not have backticks, -so we cannot write code spans properly in this readme.) - [rust-lang]: https://www.rust-lang.org/ [issues]: https://github.com/ansuz/RIIR/issues/ [memory-safe]: https://trac.torproject.org/projects/tor/ticket/11331