In short: In this case, since X
does not implement Drop
, storing None
is done in a single instruction. The number of CPU cycles depends heavily on the exact hardware and on caching effects. But assuming a modern x86-64 CPU and assuming the memory is in L1 cache (fair assumption for stack memory), it should only be a couple cycles.
To get meaningful assembly out of your program, I added two black_box
calls to simulate using the value of your variable. I also made the value inside the array 13 as 0 is often treated in a special case.
let mut x : Option<X> = Some([13; 256]);
std::hint::black_box(&x);
x = None; // how many CPU ticks here?
std::hint::black_box(x);
Compiling that code in the Compiler Explorer gives the following assembly (commented by me):
.LCPI0_0:
.zero 16,13 ; 16 bytes with value 13
example::foo:
; reserve space on the stack
sub rsp, 144
; Copy the xmmword (16 bytes) from the constant location LCPI0_0 to the
; register xmm0.
movaps xmm0, xmmword ptr [rip + .LCPI0_0]
; Copy the register xmm0 (now containing a bunch of 13s) to all these memory
; locations (relative to the rsp register)
movups xmmword ptr [rsp + 121], xmm0
movups xmmword ptr [rsp + 105], xmm0
movups xmmword ptr [rsp + 89], xmm0
movups xmmword ptr [rsp + 73], xmm0
movups xmmword ptr [rsp + 57], xmm0
movups xmmword ptr [rsp + 41], xmm0
movups xmmword ptr [rsp + 25], xmm0
movups xmmword ptr [rsp + 9], xmm0
movups xmmword ptr [rsp - 7], xmm0
movups xmmword ptr [rsp - 23], xmm0
movups xmmword ptr [rsp - 39], xmm0
movups xmmword ptr [rsp - 55], xmm0
movups xmmword ptr [rsp - 71], xmm0
movups xmmword ptr [rsp - 87], xmm0
movups xmmword ptr [rsp - 103], xmm0
movups xmmword ptr [rsp - 119], xmm0
; Move 1 to that single memory location
mov byte ptr [rsp - 120], 1
; Prepare parameters for black_box call -> ignore that
lea rax, [rsp - 120]
mov qword ptr [rsp - 128], rax
lea rcx, [rsp - 128]
; Write None to the variable <--- LOOK HERE
mov byte ptr [rsp - 120], 0
; Prepare parameters for black_box call again -> ignore that
mov qword ptr [rsp - 128], rax
; Function outro: "clean" stack space and return from function
add rsp, 144
ret
As you can see (assuming you trust my comments), storing a None
here takes only one instruction, a mov byte
one. This is one of the easiest instructions, but also one of the hardest to estimate the time of. Why? CPU-caching. Assuming the data is in L1 cache, this should be only a couple of CPU cycles. If the memory is not in any cache (unlikely for the stack), then it could take hundreds of cycles.
Also worth noting: this is so simple because the replaced data were just simple bytes and no cleanup was needed. If the T
in Option<T>
implements Drop
, the drop function needs to be called at this point, making it a lot more complicated.
Why can this be done with only one byte stored you ask? Well, enums in Rust (which Option
is) are generally stored like this:
┌─────┬─────────────┐
│ tag │ contents... │
└─────┴─────────────┘
The tag, or discriminator, just stores what variant of the enum (None
or Some
) is currently active. After that, the data area begins, where the data belonging to the active variant is stored.