Search
Is there a way to detect all structs in the current crate that implement a certain trait?
Hi all.
I want to develop a plugin system within my program, and I have a trait that functions defined by plugins should implement.
Currently, my code gets all the functions in a HashMap and then calls them by their name. Problem is, I have to create that hashmap myself by inserting every function myself.
I would really appreciate it if there was a way to say, suppose, all pub members of mod functions::
that implement this trait PluginFunction
call register(hashmap)
function. So as I add more functions as mod
in functions
it'll be automatically added on compile.
Pseudocode:
Files:
src/ ├── attrs.rs ├── functions │ ├── attrs.rs │ ├── export.rs │ └── render.rs ├── functions.rs ├── lib.rs
Basically, in mod functions
I want:
impl AllFunctions{ pub fn new() -> Self { let mut functions_map = HashMap::new();[[ register_all!(crate::functions::* implementing PluginFunction, &mut functions_map); Self { function_map } } }
Right now I'm doing:
impl AllFunctions{ pub fn new() -> Self { let mut functions_map = HashMap::new();[[ crate::functions::attrs::PrintAttr{}.register(&mut functions_map); crate::functions::export::ExportCSV{}.register(&mut functions_map); crate::functions::render::RenderText{}.register(&mut functions_map); // More as I add more functions Self { function_map } } }
World Wonders Explorer - small Leptos site demoing a free API I built
Hey all, just sharing a small, single-page site I built using Leptos + TailwindCSS, mainly intended as a demo for an API I built using Axum. Hope someone also finds it interesting!
I'm sharing this site and not the API itself cause I figure it's easier to look at and understand, but if you want to roast some code I would appreciate any feedback you have on the API itself (repo here). Trying to leave the front end developer scene so this is the first API I've tried building, fairly basic but it was fun (I am a big Civ V fan - I hear it's inspired by some niche thing called human history?).
Edit: whoops, looks like the link didn't get set cause I put an image - the site is available here, and the repo for it is here. The live API is available here
Asterinas linux abi compatible OS core in Rust
After reading Drew's pitch to the rust community to write our own kernel, I've searched for "linux abi compatible rust kernel" and found "Asterinas". Surprised that it is not mentioned here
Treedome 0.5.0: Local Encrypted Notes with Modern Features
A local-first, encrypted, note taking application organized in tree-like structures
cross-posted from: https://programming.dev/post/18265389
>Hello again everyone, Dihar here. It's been a while since the last release of treedome, but here you go! This release is all about UI update, emojis, and bug fixes. Please consult this git diff
for a more detailed changelog https://codeberg.org/solver-orgz/treedome/compare/0.4.5...0.5.0. These are the highlight of the release.
>
> !
>
> * Add emoji picker for title, will show up in tree!
> * Text Editor toolbar is back, now with option to toggle both toolbar and floating menu independently!
> * Checkbox is here! Thanks Mantine UI!
> * You can check the size of each notes by navigating to Escape Menu -> Configure -> Show Note Sizes!
> * Add created/last modified date in notes. Note created before this will not have this field and will set as today's date!
> * Create child note can now be done through dropdown instead of only from shortcuts!
> * Fix bugs of saving empty tree
> * General UI update and more stability for auto scrolling in tree view
> * Documentation update
Debug-time enforcement of borrowing rules, and safety in general.
Another crazy idea I share with this website.
I was developing a game and an engine in Rust, so I was reading many articles, most of which criticize the 'borrow checker'.
I know that Rust is a big agenda language, and the extreme 'borrow checker' shows that, but if it weren't for the checker, Rust would be a straight-up better C++ for Game development, so I thought: "Why not just use unsafe
?", but the truth is: unsafe
is not ergonomic, and so is Refcell<T>
so after thinking for a bit, I came up with this pattern:
let mut enemies = if cfg!(debug_assertions) { // We use `expect()` in debug mode as a layer of safety in order // to detect any possibility of undefined bahavior. enemies.expect("*message*"); } else { // SAFETY: The `if` statement (if self.body.overlaps...) must // run only once, and it is the only thing that can make // `self.enemies == None`. unsafe { enemies.unwrap_unchecked() } };
You can also use the same pattern to create a RefCell<T>
clone that only does its checks in 'debug' mode, but I didn't test that; it's too much of an investment until I get feedback for the idea.
This has several benefits:
1 - No performance drawbacks, the compiler optimizes away the if
statement if opt-level
is 1 or more. (source: Compiler Explorer)
2 - It's as safe as expect()
for all practical use cases, since you'll run the game in debug mode 1000s of times, and you'll know it doesn't produce Undefined Behavior
If it doesn't crash.
You can also wrap it in a "safe" API for convenience:
``` // The 'U' stands for 'unsafe'. pub trait UnwrapUExt { type Target;
fn unwrap_u(self) -> Self::Target; }
impl<T> UnwrapUExt for Option<T> { type Target = T;
fn unwrap_u(self) -> Self::Target { if cfg!(debug_assertions) { self.unwrap() } else { unsafe { self.unwrap_unchecked() } } } } ```
I imagine you can do many cool things with these probably-safe APIs, an example of which is macroquad's possibly unsound usage of get_context()
to acquire a static mut
variable.
Game development is a risky business, and while borrow-checking by default is nice, just like immutability-by-default, we shouldn't feel bad about disabling it, as forcing it upon ourselves is like forcing immutability, just like Haskell does, and while it has 100% side-effect safety, you don't use much software that's written in Haskell, do you?
Conclusion: we shouldn't fear unsafe
even when it's probably unsafe, and we must remember that we're programming a computer, a machine built upon chaotic mutable state, and that our languages are but an abstraction around assembly.
graydon/rust-prehistory: historical archive of rust pre-publication development
historical archive of rust pre-publication development - graydon/rust-prehistory
Excerpt:
> This is a reconstruction -- extracted and very lightly edited -- of the "prehistory" of Rust development, when it was a personal project between 2006-2009 and, after late 2009, a Mozilla project conducted in private. > > The purposes of publishing this now are: > > - It might encourage someone with a hobby project to persevere > - It might be of interest to language or CS researchers someday > - It might settle some arguments / disputed historical claims
Rust started being developed 18 years ago. This is how it looked until 14 years ago, where I believe the rest of development is on rust-lang/rust. The first Rust program looks completely different than the Rust we know today.
A table of publicly available Arena crates and their features
Sometimes you just really need an arena. Sometimes for performance reasons, other times for lifetime-related reasons. In their most basic forms, they're just a vec with some extra guarantees. However, it's those extra guarantees that matter. I've found myself looking for the right kind of arena too ...
For a technical discussion of using arenas for memory allocation with an example implementation, see gingerBill's Memory Allocation Strategies - Part 2: Linear/Arena Allocators
COSMIC ALPHA 1 Released (Desktop Environment Written In Rust From System76)
System76 computers empower the world's curious and capable makers of tomorrow
How do I parse the escape characters of the content of a string literal input with nom?
So, I'm basically trying to parse a string literal with nom. This is the code I've come up with:
```rust use nom::{ bytes::complete::{tag, take_until}, sequence::delimited, IResult, };
/// Parses string literals. fn parse_literal<'a>(input: &'a str) -> IResult<&'a str, &'a str> { // escape tag identifier is the same as delimiter, obviously let escape_tag_identifier = input .chars() .nth(0) .ok_or(nom::Err::Error(nom::error::Error::new( input, nom::error::ErrorKind::Verify, )))?;
let (remaining, value) = delimited( tag(escape_tag_identifier.to_string().as_str()), take_until(match escape_tag_identifier { '\'' => "'", '"' => "\"", _ => unreachable!("parse_literal>>take_until branched into unreachable."), }), tag(escape_tag_identifier.to_string().as_str()), )(input)?;
Ok((remaining, value)) }
#[cfg(test)] mod literal_tests { use super::*;
#[rstest] #[case(r#""foo""#, "foo")] #[case(r#""foo bar""#, "foo bar")] #[case(r#""foo \" bar""#, r#"foo " bar"#)] fn test_dquotes(#[case] input: &str, #[case] expected_output: &str) { let result = parse_literal(input); assert_eq!(result, Ok(("", expected_output))); }
#[rstest] #[case("'foo'", "foo")] #[case("'foo bar'", "foo bar")] #[case(r#"'foo \' bar'"#, "foo ' bar")] fn test_squotes(#[case] input: &str, #[case] expected_output: &str) { let result = parse_literal(input); assert_eq!(result, Ok(("", expected_output))); }
#[rstest] #[case(r#""foo'"#, "foo'")] #[case(r#"'foo""#, r#"foo""#)] fn test_errs(#[case] input: &str, #[case] expected_err_input: &str) { let result = parse_literal(input); assert_eq!( result, Err(nom::Err::Error(nom::error::Error::new( expected_err_input, nom::error::ErrorKind::TakeUntil ))), ); } } ```
> Note: The example uses rstest
for tests.
Although it looks a little bit complex, actually, it is not. Basically, the parse function is parse_literal
. The tests are separated for double quotes and single quotes and errors.,
When you run the tests, you will realize first and second cases for single and double quotes run successfully. The problem is with the third case of each: #[case(r#""foo \" bar""#, r#"foo " bar"#)]
for test_dquotes
and #[case(r#"'foo \' bar'"#, "foo ' bar")]
for test_squotes
.
Ideally, if a string literal is defined with single quotes and has single quotes in its content, the single quotes can be escaped with single quotes again. Same goes for double quotes as well. To demonstrate in a pseudocode:
plain "foo ' bar" // is ok "foo \" bar" // is ok "foo " bar" // is err 'foo " bar' // is ok 'foo \' bar' // is ok 'foo ' bar' // is err
Currently, in the code, I take characters until the delimiter with take_until
, which reaches to the end of the input
, which, let's say, in this case, is guaranteed to contain only and only the string literal as input. So it's kind of okay for first and second cases in the tests.
But, of course, this fails in the third cases of each test since the input
has the delimiter character early on, finishes early and returns the remaining.
This is only for research purposes, so you do not need to give a fully-featured answer. A pathway is, as well, appreciated.
Thanks in advance.
System76 with Jeremy Soller | Rust in Production Podcast S02 E07 by corrode Rust Consulting | 2024-07-25
Many devs dream of one day writing their own operating system. Ideally in their favorite language: Rust. For many of us, this dream remains just that: a dream. Jeremy Soller from System76, however, didn't just contribute kernel code for Pop!_OS, but also started his own operating system, RedoxOS, wh...
> Many devs dream of one day writing their own operating system. Ideally in their favorite language: Rust. For many of us, this dream remains just that: a dream. > > Jeremy Soller from System76, however, didn't just contribute kernel code for Pop!_OS, but also started his own operating system, RedoxOS, which is completely written in Rust. One might get the impression that he likes to tinker with low-level code! > > In this episode of Rust in Production, Jeremy talks about his journey. From getting hired as a kernel developer at Denver-based company System76 after looking at the job ad for 1 month and finally applying, to being the maintainer of not one but two operating systems, additional system tools, and the Rust-based Cosmic desktop. We'll talk about why it's hard to write correct C code even for exceptional developers like Jeremy and why Rust is so great for refactoring and sharing code across different levels of abstraction.
Listen to Rust in Production Podcast S02 E07
Jiff is a new date-time library for Rust that encourages you to jump into the pit of success
A date-time library for Rust that encourages you to jump into the pit of success. - BurntSushi/jiff
Anyone looking for a fun small rust project? Create a crate for cleaning urls, based on the ClearUrls project
cross-posted from: https://lemmy.ml/post/18162485
> This would entail:
>
> - Pulling in the ClearUrls rules as a git submodule.
> - Reading / transforming the json there into Rust structs.
> - Creating a Rust crate that runs a .clean(input_url) -> String
>
> Lemmy issue: https://github.com/LemmyNet/lemmy/issues/4905
diesel_async 0.5 released, with SQlite support
Added type diesel_async::pooled_connection::mobc::PooledConnection MySQL/MariaDB now use CLIENT_FOUND_ROWS capability to allow consistent behaviour with PostgreSQL regarding return value of UPDATe ...
> - Added type diesel_async::pooled_connection::mobc::PooledConnection
> - MySQL/MariaDB now use CLIENT_FOUND_ROWS
capability to allow consistent behaviour with PostgreSQL regarding return value of UPDATe
commands.
> - The minimal supported rust version is now 1.78.0
> - Add a SyncConnectionWrapper
type that turns a sync connection into an async one. This enables SQLite support for diesel-async
> - Add support for diesel::connection::Instrumentation
to support logging and other instrumentation for any of the provided connection impls.
> - Bump minimal supported mysql_async
version to 0.34
>
> A special thanks goes to @momobel and Wattsense for contributing the SyncConnectionWrapper
implementation.
>
> To support future development efforts, please consider sponsoring me on GitHub.
>
> Full Changelog: v0.4.0...v0.5.0
Ferris is now on the Fediverse Canvas!
I hope this slightly off-topic post is ok here. Today the Fediverse Canvas 2024 event begun and I thought it would be nice to add Ferris to the canvas. I started with a couple of pixels, but after a while I got distracted with other things. When I came back, I found that some of you have already finished it 🦀
Btw. Ferris sits on top of the Godot logo (bottom and slightly right).
Should RustSec (Advisory Database and Cargo tools) be embraced at the foundational level and made a "mandatory best practice"?
Security advisory database for Rust crates published through https://crates.io
Hi all,
ref: https://programming.dev/post/16349359
I agree with all the criticism about the author, the intentions, and the points in the article, expressed in the ref. thread. I also think the author highlights a serious issue (if we leave "selling the book", cheap criticism, and sensationalism aside). While nothing new for most developers, the article has spawned a personal rabbit hole of discovery, starting from supply chain attacks.
I am still very early in my process of learning Rust (still reading The Book) and self-taught software engineering in general, and the journey the article has spawned was very educational to me. I've learned about securing software and being mindful across the whole SDLC[1], AppSec, DevSec, OWASP, SLSA[2] Socket[3], GitHub Advanced Security, and many more tools and guidelines. Last of which is RustSec[4]. Which quenched my thirst and closed that personal rabbit hole. It has opened a different can of worms though.
While endemic to any non-monolithic ecosystem and only part of the "big security picture", supply chain is possibly the major player across the spectrum. Comparable to "the legacy issue" of stagnating systems and infrastructures, open to exploits as old as the Sun.
Now, while I am aware that security is a process, not a product and that this is easier said than done: I wonder if tools like RustSec should be embraced at the foundational level and made a "mandatory best practice". RustSec tools integrate with an up to date security advisory database and Cargo. They can also be deployed as GitHub Actions.
Because I am sure this is not all roses: I agree that (for example) dependabot is seen as a major annoyance more than a useful tools for a number of reasons, and that RustSec could spark the same kind of thoughts. However, it could be a great stepping stone of the security process.
I am aware I may be being too idealistic here, but the process has to start from somewhere and stagnating on "dogmas" ain't helping either.
Please be kind in your replies.
Cheers
[1] https://www.youtube.com/watch?v=hDvz8KivY_U [2] https://slsa.dev [3] https://socket.dev [4] https://rustsec.org
Rust has a HUGE supply chain security problem | Sylvain Kerkour | July 2, 2024
July 2, 2024
Sylvain Kerkour writes:
> Rust adoption is stagnating not because it's missing some feature pushed by programming language theory enthusiasts, but because of a lack of focus on solving the practical problems that developers are facing every day. > > ... no company outside of AWS is making SDKs for Rust ... it has no official HTTP library. > > As a result of Rust's lack of official packages, even its core infrastructure components need to import hundreds of third-party crates. > > - cargo imports over 400 crates. > > - crates.io has over 500 transitive dependencies. > > ...the offical libsignal (from the Signal messaging app) uses 500 third-party packages. > > ... what is really inside these packages. It has been found last month that among the 999 most popular packages on crates.io, the content of around 20% of these doesn't even match the content of their Git repository. > > ...how I would do it (there may be better ways): > > A stdx (for std eXtended) under the rust-lang organization containing the most-needed packages. ... to make it secure: all packages in stdx can only import packages from std or stdx. No third-party imports. No supply-chain risks.
[stdx packages to include, among others]:
> gzip, hex, http, json, net, rand
Read Rust has a HUGE supply chain security problem
---
Submitter's note:
I find the author's writing style immature, sensationalist, and tiresome, but they raise a number of what appear to be solid points, some of which are highlighted above.
@thevoidzero not doom/space just regular emacs with vterm ( 29±)
rust is nightly on nixos 24.11 last I checked
in a devshell
rust setup
https://git.sr.ht/~carnotweat/morning-rust
Oh, this is great! I had a few usecases for this back in the day, but never bothered implementing any of the algorithms myself. Do you use these yourself? (from the name I assume you're the author?)
No, macros can see only the tokens you give them. They have no notion of the fact that crate::functions
is a module, that PluginFunction
is a trait and that functions_map
is a variable. Not even the compiler may know those informations when the macro is expanded.
If you really really want to do this, you can use something like inventory
. Note that inventory
uses a special linker section to do this, which some consider a hack. This is also not supported on WASM if you want to target it.
I have observed people taking Rust seriously. You need to reexamine your assumptions.
We have an evolved capability to short-circuit decisions with a rapid emotional evaluation. It means as a species we didn't die out early ["that's a lion; I'm a oerson; lions eat people ergo... Agh!" is not a sustainable strategy] - what's amazing is that we can also apply it to elarned abstract things like an aestetic sense about programming languages. Such instincts aren't always perfect, but they're still worth paying attention to. I don't see a reason not to express that in a blog post, but you can replace it with "this is unergonomic and in some cases imprecise" if you prefer.
It's a subtle difference between that and path::exists()
.
path::exists()
==false
might just mean you can't use it (if path::exists() cannot access a file due to e.g. permissions, it'll return false)fs::exists()
==Ok(false)
means it's definitely not there (permissions error will cause an Err to be returned)
Oh wow.. This might be what the rust in Linux people need to switch to. Fuck all the LKML bullshit, fuck mailinglists, fuck C, fuck the shitty tooling and hodgepodge of languages. This looks amazing. Seriously, cargo run and the kernel starts up in a VM? How friggin cool is that?
Wow...
Again, the Linux kernel needs more funding. For crying out loud, these kinds of people holding back progress should be made obsolete (by bringing in and paying talent that is willing to work towards a brighter future with less memory errors, a sane tech stack with better tooling, and better processes). Holding back progress because of their incessant pearl clutching "but my dearest C!!!" Just hurts everybody and impedes progress.
Of course blindly adding the latest and greatest is asking for trouble. Assessing risk, weighing options, making a plan and continuously assessing impact is definitely important, but straight up blocking the road on principle is extremely unproductive.
but futures only execute when polled.
The most interesting part here is the polling only has to take place on the scope itself. That was actually what I wanted to check, but got distracted because all spawns are awaited in the scope in moro
's README example.
async fn slp() {
tokio::time::sleep(std::time::Duration::from_millis(1)).await
}
async fn _main() {
let result_fut = moro::async_scope!(|scope| {
dbg!("d1");
scope.spawn(async {
dbg!("f1a");
slp().await;
slp().await;
slp().await;
dbg!("f1b");
});
dbg!("d2"); // 11
scope.spawn(async {
dbg!("f2a");
slp().await;
slp().await;
dbg!("f2b");
});
dbg!("d3"); // 14
scope.spawn(async {
dbg!("f3a");
slp().await;
dbg!("f3b");
});
dbg!("d4");
async { dbg!("b1"); } // never executes
});
slp().await;
dbg!("o1");
let _ = result_fut.await;
}
fn main() {
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(_main())
}
[src/main.rs:32:5] "o1" = "o1"
[src/main.rs:7:9] "d1" = "d1"
[src/main.rs:15:9] "d2" = "d2"
[src/main.rs:22:9] "d3" = "d3"
[src/main.rs:28:9] "d4" = "d4"
[src/main.rs:9:13] "f1a" = "f1a"
[src/main.rs:17:13] "f2a" = "f2a"
[src/main.rs:24:13] "f3a" = "f3a"
[src/main.rs:26:13] "f3b" = "f3b"
[src/main.rs:20:13] "f2b" = "f2b"
[src/main.rs:13:13] "f1b" = "f1b"
The non-awaited jobs are run concurrently as the moro docs say. But what if we immediately await f2?
[src/main.rs:32:5] "o1" = "o1"
[src/main.rs:7:9] "d1" = "d1"
[src/main.rs:15:9] "d2" = "d2"
[src/main.rs:9:13] "f1a" = "f1a"
[src/main.rs:17:13] "f2a" = "f2a"
[src/main.rs:20:13] "f2b" = "f2b"
[src/main.rs:22:9] "d3" = "d3"
[src/main.rs:28:9] "d4" = "d4"
[src/main.rs:24:13] "f3a" = "f3a"
[src/main.rs:13:13] "f1b" = "f1b"
[src/main.rs:26:13] "f3b" = "f3b"
f1 and f2 are run concurrently, f3 is run after f2 finishes, but doesn't have to wait for f1 to finish, which is maybe obvious, but... (see below).
So two things here:
- Re-using the spawn terminology here irks me for some reason. I don't know what would be better though. Would
defer_to_scope()
be confusing if the job is awaited in the scope? - Even if assumed obvious, a note about execution order when there is a mix of awaited and non-awaited jobs is worth adding to the documentation IMHO.
I skimmed the latter parts of this post since I felt like I read it all before, but I think moro
is new to me. I was intrigued to find out how scoped span
exactly behaves.
async fn slp() {
tokio::time::sleep(std::time::Duration::from_millis(1)).await
}
async fn _main() {
let value = 22;
let result_fut = moro::async_scope!(|scope| {
dbg!(); // line 8
let future1 = scope.spawn(async {
slp().await;
dbg!(); // line 11
let future2 = scope.spawn(async {
slp().await;
dbg!(); // line 14
value // access stack values that outlive scope
});
slp().await;
dbg!(); // line 18
let v = future2.await * 2;
v
});
slp().await;
dbg!(); // line 25
let v = future1.await * 2;
slp().await;
dbg!(); // line 28
v
});
slp().await;
dbg!(); // line 32
let result = result_fut.await;
eprintln!("{result}"); // prints 88
}
fn main() {
// same output with `new_current_thread()` of course
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(_main())
}
This prints:
[src/main.rs:32:5]
[src/main.rs:8:9]
[src/main.rs:25:9]
[src/main.rs:11:13]
[src/main.rs:18:13]
[src/main.rs:14:17]
[src/main.rs:28:9]
88
So scoped spawn
doesn't really spawn tasks as one might mistakenly think!
How much more? When it comes to whether I'd write GPU drivers for money, I can tell you that LF doesn't pay enough, Collabora doesn't pay enough, Red Hat doesn't pay enough, and Google illegally depressed my salary. Due to their shitty reputation, Apple, Meta, or nVidia cannot pay enough. And AMD only hires one open-source developer every few years. Special shoutout to Intel, who is too incompetent to consider as an employer.
Breaking that kind of API probably breaks users pace. Linus is very vocal about breaking userpace.
This is basically what you said here, and it's still wrong: social dynamics, not money, is the main reason why young hackers (don't) work on Linux. I'm starting to suspect that you've not hacked kernel before.
It's such a shame that Rust developers feel like they feel unwelcome, especially due to a complete misunderstanding in implementation details.
Even worrying, this is kernel developers saying they prioritise their own convenience over end user safety.
Google has been on a Rust adoption scheme, and it seems to have done wonders on Android: https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html?m=1
But also, there is a bit of a problem to adopt Rust. I think the memory model may prove challenging to some, but I do worry in this case that even if it was super simple, the existing C kernel devs would still reject the code due to it not being C and not willing to adopt a new language.
Nearly expected. The Linux Foundation doesn't spend nearly enough money on the linux kernel to get new blood into it willing to contribute what is necessary (in this case Rust).
It seems it would be a lot easier to work on the GCC compiler, and work with others to bootstrap GCC (if it hasn't already been done). Getting the GCC Rust compiler able to compile some version of rustc probably wouldn't be that hard, and then you can just use that version to compile up the chain to modern Rust.
A lot of this bootstrapping stuff comes back to the 'trusting trust' attack. You could write a compiler that adds some malicious code to programs it compiles. But the thing is, it could also insert it's own malicious code when compiling a compiler. So you look at your code, and the code of your compiler, and everything looks fine, but the exploit is still there. Someone wrote an example in rust.
Theoretically there could also be bugs that propagate this way. So to fully trust your code is doing what you think it is, you'd need a chain of compilers back to hand coded assembly.
Then there is the question of where the CPU is supposed to come from. Any modern one was designed using lots of mysterious CAD tools. Maybe scrounge a vintage Z80 out of an old Timex-Sinclair or something?
The main thing is that TinyCC has already been bootstrapped.
Check out this page on bootstrappable.org. Basically they start with a 200 something byte binary (hex0) that can act as an assembler, then using a bunch of layers of tools and compilers you can bootstrap a whole system. I think they use stage0 to build M2-Planet, use that to build GNU Mes, and use that to build TinyCC.
So a project like this fits neatly into that bootstrapping path. It could be done other ways, but starting from a fairly complete C compiler makes it a lot easier than building an entire path from scratch.
i'm tricking the nintendo switch into thinking my computer is a bluetooth pro controller. I'm using a crate called bluer which exposes bindings to the BlueZ stack and it's been great to use.
I got to the point where it pairs the controller and hits B to exit. However it doesnt seem to accept any more button presses after that... :) So I have some ways to go.
I've also needed a project where I can challenge myself with the basics of async without it being overwhelming, and I think this hits the sweet spot. It's my first time using tokio spawn, join, and select in a real project!
Rewriting huge parts of the IDL compiler for Nucom, my implementation of Microsoft’s COM binary interface standard and (in the future) network protocol. The original version was hacked together with a lot of assumptions made in the parser and isn’t very extensible, and I do need to extend it now.
(Nucom is another way to have a stable ABI for Rust, e.g. for a plugin interface, and for Rust/C++ (and more OOP-style C) interop, based on objects with vtable pointers. And hopefully sometime in the future, transparent IPC and networking so you don’t have to load plugins into your process’s memory space if they don’t need to be there, with it working the same as if it were direct calls. All of this I assume you can already do on Windows with the windows-rs crate but it's obviously Windows-only.)
I do have to say though, I need a better way of transforming my syntax tree. Right now I’m just copying the struct definitions over and over for each compile stage and manually writing code to copy everything instead of just the parts I’m actually transforming, and it just seems like there has to be a better way. I might want another proc macro for this.