The smallest binary rustc has ever produced on x86_64 is 137 bytes: https://github.com/dgotrik/tiny-rust-executable
The projects I work on are in the 32 bit ARM space, so we have more space than the projects you're talking about, but we use a microkernel, compile all programs separately, and then put them all together at the end. Some example programs and sizes:
* kernel: 32k flash, 8k RAM
* supervisor task: 8k flash, 2k RAM
* SPI tasks: 16k flash, 2k RAM
* I2C task: 16k flash, 2k RAM
* sensors task: 8k flash, 8k RAM
* an "idle" do-nothing task: 128 bytes flash, 256 bytes RAM
(Note that some of these are larger than is actually required, I got these numbers by checking in on the amount of memory space they request from the OS, which has to be a power of 2 in the current implementation, so something that's 4097 bytes ends up being 8k in these numbers.)
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
I use rust on 8bits micro controllers with 128 bytes of RAM and enough flash to store about 1000 instructions.
Enough to decode standard 433mhz radio remotes, learn them, store and recall into eeprom and drive a dozen LEDs and a button for the UX.
Is that maybe what you were referring to?
For certain scalar types, flexibility is increased by allowing 'copy' semantics where assigning 'a' into 'b' makes 'b' a copy of 'a', and both are alive. Then it ends up mattering how heavy the type is - although you can only implement 'copy' for things you can trivially memcpy, so nothing on the heap.
Generally anything that would be expensive to duplicate doesn't get 'copy' semantics, but instead requires you to move it into a new variable, or explicitly clone it.
Rust also has immutable-by-default semantics, but it's by default. You can mutate the contents of structs, but there can only be one mutable reference XOR an arbitrary quantity of read-only references and aliasing is not permitted. This forms the basis for many of the safety guarantees.
Did that help? I was guessing at what you meant, so if that wasn't it I can always try again.
[edit] within the context of microcontrollers Rust requires you to be very explicit about what is and isn't permitted, and how things should work. You can disallow in your construction pretty much anything expensive or non-trivial.
Natively the CPU deals with 8-bit values. Obviously that's a little cramped so you can just about get away with using a few more instructions to do 16-bit. If you absolutely must, 32-bit ints aren't horrible to cope with, but then you start to get into a lot of unnecessary code when you want to change size.
Even a very high level language like C is a bad idea on something so constrained, because C assumes that everything is a massive approximately VAX-like architecture with mappable memory all over the place, and limitless amounts of it, possibly as much as one or two megabytes.
That's not really true for the AVR family; the instruction set and general architecture was designed with C in mind. Unlike say a PIC microcontroller, the AVR family has a hardware stack pointer (SPH/SPL) and a large number of 8-bit registers which can also be referenced in 16-bit pairs for the (albeit limited) set of instructions which support it.
C makes some assumptions (for instance assuming the existence of a stack pointer), but the AVR designers kept that stuff in mind. Pretty sure AVR C actually uses ILP16 data model, not an 8-bit model as you may be expecting.
C doesn't make assumptions about the size of an address space, although you can when specifying the data model for your architecture.
The only thing that's slightly less than clean programming AVRs using C is that they're Harvard architecture instead of Von Neumann so you have to access program memory via special instructions (lpm/elpm/spm). That's wrapped with a __attribute__((progmem)) specifier in AVR GCC so the compiler knows it uses a different address space.
I don’t see why this a problem. Both C and Rust give you 8 bit and 16 bit types to work with. It’s true that you may sometimes need assembly to eke out the last drops of performance on such small chips, but equally sometimes you don’t and C/C++/Rust are excellent tools for the job.
A 32-bit add will get turned into 1 8-bit add and 3 8-bit add-with-carry instructions. You won't even notice, unless to your point, you see a performance issue or start running out of code space.
where/how does C make this assumption?
Rust enforces many guarantees w.r.t. memory access & sharing at compile time, but at codegen time, it's basically as vanilla and ‶boring″ as C++.