New week, new Rust! What are you folks up to?
Creating custom Vec that supports stack and heap
It is
struct HeapStrings {
val: Vec<u8>,
spans: Vec<u64>
}
And
struct StackStrings<const BYTE: usize, const NUM: usize> {
val: [MaybeUninit<u8>; BYTE],
spans: [MaybeUninit<u64>; NUM]
}
Spans is a bit packed of 2 u32, start and len
The difference with Vec<String> and Vec<&str> is it is truly contigous, where Vec<String> has scattered heap because what contigous in it is only the String metadata not the String bytes so there are many indirections/pointer chasing when looping the elements. An owned value, so no lifetime annotation is needed because then the lifetime annotation requirement spreads to other code like impl code, parent struct etc (I hope the compiler can infer lifetime so using lifetime does not feel scary :<), where the stack version is fixed size
The downside is each individual element can't dynamically grow, only the Vector itself can grow to add more new String
I'm not sure which one is faster between bit packed and direct value like
struct Span {
start: usize,
len: usize
}
The bit packed = lesser memory + 1 load register + bitwise operation
Or direct value = higher memory + 2 load register
I'm still trying to find the better in term of execution speed not memory usage :<
Adding an --example mnist bin to my hypervector crate - classification of handwritten digits.
.@
.. :*
:* :@
@* @*
@* *@:
@* *@.
:@* @@
*@: *@@
*@. .*@@.
*@. :::@@@*@@
:@@@@@@@@@*:. @@
:*****.. .@@
*@:
*@.
*@.
*@.
*@.
*@:
*@:
.@:
adding file transfers and encryption to my chat server/client 8080_msg
Working on my new database software, just did my usual super-simple benchmark:
Source='schema test'
Schema test created
elapsed micros=33
Source='table test.users (name string, age int)'
Table Created STable { id: 2, dt: Struct([("Id", Int), ("name", String(50)), ("age", Int)]) }
elapsed micros=32
Source='let i = 8192
while i > 0 { insert into test.users(name,age) values ('Alice', 1000) set i = i - 1 }'
elapsed micros=7156
Source='let total=0 for x = age from test.users set total = total + x select total'
Int(8192000)
elapsed micros=900
This (980 micros) is very roughly than 3 x faster than SqlLite, and 2.5 x faster than my previous database software, so it is encouraging. It should be significantly faster at responding to short read-only queries, as it has a shared pre-calculated global schema which stores table type info and functions.
A lot of updates to a GPU fan controller specifically for Nvidia gpus running on linux. The fan ramp up under heavy load from the Nvidia drivers is too slow to act. My controller is far more aggressive as load and temp go up.
Now, because I'm paranoid of damage as a result of thermal cycling, there are...
- A dedicated thermal control module that...
- Now has three cooling regimes
- A hysteresis band to maintain warmth between heavy runs/loads (lessen temp differentials)
- A low power inactive mode (so the room doesn't warm up! LOL)
- Debugging argument
- Initial inclusion of the nvml::wrapper / will convert too this from calls to cli command tools.
It's been fun. ![]()
I was heavily working on GitHub - PaulmannLighting/ezsp: The EmberZNet Serial Protocol · GitHub and on GitHub - PaulmannLighting/apis-saltans: Rust library implementing a smart home protocol of dancing insects. · GitHub.
Getting the EZSP incoming frame defragmentation right was a hassle, partially due to sparse documentation on that.
In the meantime I integrated Diesel with SQLite into our (proprietary) Gateway controller.
This was pretty fun due to the compiled binary crashing with an Illegal Instruction on the target ARMv7 system. I worked heavily with Codex to pin down the underlying issue and it seems like during the SQLite database loading the path canonicalization did some weird stuff that triggered a LLVM stack canary. Codex came up with a lot of black magic trying to combat that, but for those interested, the binary no longer crashes when compiled with these settings:
[env]
CC_armv7_unknown_linux_musleabihf = "clang"
CFLAGS_armv7_unknown_linux_musleabihf = "--target=armv7-unknown-linux-musleabihf -nostdinc -isystem /usr/lib/clang/22/include -isystem /usr/lib/zig/libc/include/arm-linux-musl -isystem /usr/lib/zig/libc/include/arm-linux-any -isystem /usr/lib/zig/libc/include/generic-musl -isystem /usr/lib/zig/libc/include/any-linux-any -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mno-unaligned-access"
Why is it always such a hassle with libraries that link to C code...?
Porting / rewriting a Python graph library (I am the author, and maintainer for years now) in Rust. I have worked on it for 9 month now, and I bet I will need another 12 months before I will release it. A long time. But also much fun, and many learnings… (I will not report this again next week ![]()
E2E Encryption? ![]()
Not sure but I am new here and i would like to learn with Rust to make something in graphic 2D at starting ![]()
But it's more the frameworks for games ![]()
Thanks for sharing !
Just encrpytion via tls, although I’m currently implementing file transfers because tls gives me a head ache
If you just want to fill a buffer and blit it to the screen I would suggest minifb.
minifb is super simple to figure out and get something up that works. Just update the logic in one of the examples. I think I used it for my first 'graphic 2d' pattern in rust.
Oh flashback!! check this out, it still works.....
Put this in your Cargo.toml
[dependencies]
minifb = "0.28.0"
And make a file called.
src/bin/thobber.rs
use minifb::{Key, Window, WindowOptions};
const WIDTH: usize = 1001;
const HEIGHT: usize = 1001;
fn main() {
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
let mut window = Window::new(
"Test - ESC to exit",
WIDTH,
HEIGHT,
WindowOptions::default(),
)
.unwrap_or_else(|e| {
panic!("{}", e);
});
// Limit to max ~60 fps update rate
window.limit_update_rate(Some(std::time::Duration::from_micros(16600)));
let mut cur = 0.0f32;
while window.is_open() && !window.is_key_down(Key::Escape) {
for (i, p) in buffer.iter_mut().enumerate() {
let x = (i % WIDTH) as u32;
let y = (i / WIDTH) as u32;
let x = (x as i32) - 500;
// at this point x is -500 to 500
let y = (y as i32) - 500;
let x = (x as f32) / 500.0;
// at this point x is -1.0 to 1.0
let y = (y as f32) / 500.0;
// now scale them to please...
let x = x * 13.1;
let y = y * 13.1;
let red_x_wobble = (cur / 1.00).sin() * x;
let red_y_wobble = (cur / 3.00).sin() * y;
let green_x_wobble = (cur / 1.01).sin() * x;
let green_y_wobble = (cur / 3.01).sin() * y;
let blue_x_wobble = (cur / 1.03).sin() * x;
let blue_y_wobble = (cur / 3.03).sin() * y;
let red = (((red_x_wobble).sin() * (red_y_wobble).sin()).abs() * 127.5) as u32;
let green = (((green_x_wobble).sin() * (green_y_wobble).sin()).abs() * 127.5) as u32;
let blue = (((blue_x_wobble).sin() * (blue_y_wobble).sin()).abs() * 127.5) as u32;
*p = red * 256 * 256 + green * 256 + blue;
}
window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
cur += 0.1
}
}
Best when run in "release" mode.
cargo r --release --bin throbber
You're welcome! ![]()
Do you have a plan to add E2E Encryption in a far future? ![]()
Cool one! ![]()
![]()
I mean probably not, 8080_msg is open source, so you can see how your messages are processed and encryption over tls is probably enough, although who knows? Maybe in the far far future I'll implement E2E encryption.
Nice ! I will test it later =)
Thanks for sharing !