bits 0x39 - Calender Week 05, 2024

sys programming in rust: thoughts so far

So I picked up a project from 1 year ago: a rust port of the OOStuBS tutorial OS in my uni.

https://git.sr.ht/~shrik3/rustubs

  • it’s so hard to do the easy things
  • it’s so easy to do the difficult things

At the very beginning, I was angery with the rust linter/compiler: the first feeling. You can’t have a global mutable state (e.g. tracing the cursor position on the CGA text display), or derefering a raw pointer into an array (e.g. the CGA text buffer) in the “C” way.

But as I program more, it starts to make sense. The linter/compiler is harsh on your code, but if you learn the concepts, you will have much less lose ends in your program. In the uni “OS Construction” lab we were tasked to observe the race condition on the CGA display when it comes to multi-threading. This WON’T happen to our rust code from the very beginning, because the compiler has already forced us to use interior mutability on a global object.

1
2
3
4
use spin::Mutex;
lazy_static! {
	pub static ref CGASCREEN_GLOBAL: Mutex<CGAScreen> = Mutex::new(CGAScreen::new());
}

Casting enum <=> primitive types:
it’s common practice to cast a numeric type into a enum and vice versa, but that’s not trivial for rust, you need to implement the TryFrom trait (or something alike) for your enum: Okay it makes sense because the enum discriminant is typically a subset of that numeric type, for example

1
2
3
4
5
6
7
8
9
pub enum Status {
    Good    =   0,
    Bad     =   1;
    WTF     =   2;
}

let s:u8 = some_function();
if s == Status::Good {/**/} // this won't work because different types
if (s as Status) == Status::Good {/**/} // this won't work either

For a TryFrom trait it’s something like this: I don’t like it! It’s too tedious and to write!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use core::convert::TryFrom;
impl TryFrom<u8> for Status {
  type Error = &'static str;
  fn try_from(value: u8) -> Result<Self, Self::Error> {
      match value {
          Status::Good as u8 => Ok(Status::Good),
          Status::Bad  as u8 => Ok(Status::Bad),
          Status::WTF  as u8 => Ok(Status::WTF),
          _                  => Err("bad u8 value"),
      }
  }
}

(well, this may even be incorrect). So you need more hacks for the match arm to work!

1
2
3
4
5
match value {
    value if value == Status::Good as u8 => Ok (Status::Good),
    value if value == Status::Bad  as u8 => Ok (Status::Bad),
_                                    => Err("Bad value")
}

I hate to say soo but this is just STUPID to write down in your program! Also see this:
https://github.com/rust-lang/rust/issues/11791

logically casting from u8 (char) into Status will fail if the value is more than 2. However in C we can simply throw these cases into a default bramch like this:

1
2
3
4
5
6
switch (v) {
    case Good: {/*deal with good and break*/}
    case Bad : {/*deal with bad and break*/}
    case WTF : {/*deal with Wtf and break*/}
    default:   {/*deal with unmatched case (maybe error?)*/}
}

Thankfully the crate num_enum is here to help:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
use num_enum::{IntoPrimitive, TryFromPrimitive};
#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Eq)]
#[repr(u8)]
enum Status {
	Good = 0x01,
	Bad  = 0x02,
	WTF  = 0x20,
}
// ...
if let Ok(s) = Status::try_from(var_uint8) {
    match s {
        Status::Good => {/*deal with good*/}
        // and other arms
    }
} else {
    // deal with conversion error
}

Just look at the sheer amount of downloads of this crate! >30 Million! All because it’s so hard to do easy things. And I really hope rust include this into their language libraries.

certain “infallible”? if you know something WON’T fall but the rust(libraries) require you to wrap a Result or Option? One thing to do is the if let:

1
if let Some(value) = res {/*deal with value*/}

But does this introduce runtime cost? And/Or does the compiler realize the absence of the else branch and optimize it away?

Things I really like

  • the inline assembly is very easy to use. tbh I haven’t really figured out the GNU/C inline assembly syntax, especially when it comes to clobbering. The rust asm! macro is out-of-the-box.
  • rich runtime even on bare metal: the rust runtime library comes in core and std. The core is usable on baremetal and you don’t need to rebuild the wheels like memcpy.
  • crates.io : especially for sys programming, there are stuffs like spin and bitflags… They are really handy!

Things I still can’t enjoy (perhaps due to my lack of knowledge):

  • the binary is pretty big, even in --release build.
  • cross compiling is as straight forward as C, and the cargo tool may not suffice (I’m using cargo-xbuild).
  • name mangling: perhaps it’s a must, but the mangled name is not really human readable.

(TO BE CONTINUED)

blog code in a public repo?

Why I don’t push my blog source code to a public repo? I’d like to! But I can’t for the sole reason: toggling drafts: in HUGO you mark a post a “draft” in the markdown frontmatters so it won’t get rendered into the public pages: I have a lot of such posts, be it WIP or full bullshit, I don’t want to make them public.

no more hacker news

The bot on my fedi instance gathers news from the HN API and post digests to the timeline. HN has been great, and for for the most part it still is1. But it doesn’t take long to realize the Y combinator, the capital behind HN, is never a neutral thing. Recently the YC CEO “wishes death upon” SF politicians. TBH I don’t give a fuck about either side of the beef, this is simply disgusting.

Related: https://www.jwz.org/blog/2024/01/y-combinator-ceo-wishes-death-to-sf-supervisors/

Currently I’m looking into news aggregator alternative. The TechURLs looks promising: let’s see if they have some nice APIs.


  1. Despite its sometimes broken moderation model and toxicity in the community. I recall seeing some unmoderated hate speech there but I don’t have a reference. However this is NOT what demotivated from using HW news. ↩︎

edited 26.02.2024
created 29.01.2024
EOF
[+] click to leave a comment [+]
the comment system on this blog works via email. The button
below will generate a mailto: link based on this page's url 
and invoke your email client - please edit the comment there!

[optional] even better, encrypt the email with my public key

- don't modify the subject field
- specify a nickname, otherwise your comment will be shown as   
  anonymous
- your email address will not be disclosed
- you agree that the comment is to be made public.
- to take down a comment, send the request via email.

>> SEND COMMENT <<

[BITS] - the weekly archive -
bits 0x49 - Calender Week 15, 2024 (WIP)
bits 0x48 - Calender Week 14, 2024
bits 0x47 - Calender Week 13, 2024
bits 0x46 - Calender Week 12, 2024
bits 0x45 - Calender Week 11, 2024
bits 0x44 - Calender Week 10, 2024
bits 0x43 - Calender Week 09, 2024 [VOID]
bits 0x42 - Calender Week 08, 2024 [VOID AGGREGATE]
bits 0x41 - Calender Week 07, 2024 [VOID]
bits 0x40 - Calender Week 06, 2024 [VOID]
bits 0x39 - Calender Week 05, 2024
bits 0x38 - Calender Week 04, 2024
bits 0x37 - Calender Week 03, 2024
bits 0x36 - Calender Week 02, 2024 [VOID AGGREGATE]
bits 0x35 - Calender Week 01, 2024
bits 0x34 - Calender Week 52, 2023
bits 0x33 - Calender Week 51, 2023
bits 0x32 - Calender Week 50, 2023 [VOID]
bits 0x31 - Calender Week 49, 2023
bits 0x30 - Calender Week 48, 2023
bits 0x2f - Calender Week 47, 2023
bits 0x2e - Calender Week 46, 2023
bits 0x2d - Calender Week 45, 2023
bits 0x2c - Calender Week 44, 2023
bits 0x2b - Calender Week 43, 2023
bits 0x2a - Calender Week 42, 2023