No they're in the resulting iterator
comments
Thank you for continued work on this.
In that for, all error messages have been lost. If to add such output “for” is the most elegant solution.
Yes, except rust has even stricter requirements - namely that your struct must only contain the "inherited" field and you still need to tell the rust compiler to use the special #[repr(transparent)]!
This is because the compiler is allowed - under "normal" representation rules - to rearrange basically everything about the memory layout of a struct to better suit its needs. And as far as I know this includes rearranging the location of a field which is arbitrarily deep inside other structures in your struct! As such
struct A {
foo: u8,
bar: u8,
}
struct B {
test: u8,
nested: A,
}
could theoretically be laid out as bar test foo - as opposed to e.g. foo bar for just A - in memory if the compiler determined that accessing bar at the start of the struct was overall the "best".
If, on the other hand, you use #[repr(c)] you get exactly what you just said, although the direct casting may or may not be undefined still. (I currently do not remember the relevant parts of the nomicon or other treaties I have read about this... I really need to get back into programming rust at some point!)
Quick edit: Expanded the possible memory layout of just the struct A.
Oh, a bit like inheritance in pure C? Where as long as inheriting struct puts the parent struct as first field, you can pass it to functions that use parent struct because the memory layout rules ensure that this part of memory will be exactly the same in both?
Regarding your question about the cast from const* T to UserRef<T>:
This should be legal as long as UserRef<T> is a #[repr(transparent)] wrapper over a const* T and does most of the magic through its implementation.
There are some other requirements iirc, but I am not entirely sure about them and some or all of them should be given here automatically through the architecture and/or a proper smart pointer implementation as a transparent wrapper...
I didn't realize this was posted here.
Allow me to copy my comment from another thread:
// Don't bail on the first error, but remember the worst one.
let mut worst = 0;
for file in files {
if let Err(e) = chmod_one(file) {
worst = worst.max(e.exit_code());
}
}
process::exit(worst);
This is not rustic, I feel.
files.iter()
.map(chmod_one)
.filter_map(Result::err)
is more like it.
From there, you can next() for first error, last() for last error, or fold() for max error, or collect() if you need to save all errors.
And no, static compilation doesn’t help here, because
get_user_by_namegoes through NSS, which dlopenslibnss_*modules at runtime regardless of whether your binary is statically linked.
This is not true in musl systems. I just quickly checked in a Chimera rootfs (which has a system dynamic musl libc btw).
I believe the described dlopening is one of the well known reasons why GNU libc is not suitable for static linking, unlike musl!
In Arch, this indeed loads /usr/lib/libnss_systemd.so.2.
Everyone can test this with strace id 2>&1 | egrep 'open.*\.so'.
The new Iter struct basically mirrors slice's Iter, but with poiners/pointer arithmetic used for everything (the new next() impl). PhantomData is used in both to track the lifetime of the data pointer.
I think you put it more understandable
I'm too noob to understand it all but the way I see it, the core is not about using Some instead of iter::slice but what is inside.
I understand this all is in context of Intel Software Guard Extensions about which I know nothing at all, and "UserRef states that userspace may always write to backing memory at any time, and that even &mut UserRef is not exclusive". So it seems that the design of UserRef is basically against Rust principles ("userspace may always write to backing memory"). So when the iterator is just a wrapper over slice::Iter, the code in next() relies on Rust's principles which don't align with how UserRef is supposed to behave. The proposal is to walk over ptr "manually" and return it (cast to UserRef) instead of constructing new UserRef from what slice::Iter would return in that next().map(|e| UserRef::from_ptr(e)).
But does
+pub struct Iter<'a, T: 'a + UserSafe> {
+ ptr: *const T,
really mean that one can happily cast that ptr to UserRef?
What is PhantomData and how/why using it makes any difference, when it's not being changed during iteration?
Is the UserRefdesign sound or was only a workaround some problem?
I am not an expert but I think the actual problem is in the slice::iter first getting an immutable reference to the underlying data with self.0.next() before mapping it into a UserRef<T> which is instant UB because a &T guarantees exclusivity while UserRef<T> explicitly states in its contract that it does not guarantee anything like that, even if mutably borrowed.
So in essence the problem, as I understood it, is in the step from slice -> reference to value -> User ref of value with the italic part being illegal.
A quick search gave me this looks like the course has come quite a long way (haven’t looked beyond the opening page, though)
Can someone explain how/confirm/deny that the proposed fix for this issue actually solves the problem? I think I understand the problem statement but I *fail to see how constructing a Some(&...) is in any way different than using iter::slice in terms of falsely guaranteeing immutability of user-space-backed memory.
"accidentally" as if they made anything to begin with
"Fearless Concurrency" predates "async" in rust nomenclature, and points to specific compile-time guarantees around things like thread safety and races (Send, Sync, ...).
It was around when we used event loops and the mio crate (and rayon for parallelism), with no async or await in sight (because they didn't exist yet).
Some people actually still prefer to do "concurrency" this way, especially if they wish to stay close to the abstraction level from C land. io_uring also came later which introduced a new OS low-level interface and paradigm for doing "concurrency".
"Fearless Concurrency" has nothing to do with how easy you can write async code, especially if you're someone who struggles with the language basics like ownership.
Thanks for admitting it.
skill issue
Rust ownership and async have been the worst part of my Rust experience. I normally either use a reference or copy and that solves 90% of my problems.
Rust prides itself on "fearless concurrency" but as I said, async is horrific. I've spent way too much time trying to build an pipeline that downloads data from a source and spreads it out to multiple consumers who can also pass data on or terminate gracefully. The experience left me so annoyed that I just moved to a worker based model with Kafka in between and let every worker download the file to do its processing. So much simpler.
Having to do shit concurrently in rust is amongst my biggest fears because of async. I'd rather use python or even JavaScript which have functional and easy async.
He couldn't even write the blog post himself. Why even get up in the morning at that point? Just stay in bed for your remaining human lifespan if you're not going to use it for anything.
The ownership model is Rust's core innovation. Every heap allocation has exactly one owner — the variable binding that "holds" it. Ownership can be moved to another binding, at which point the original is invalidated. It can never be silently copied (unless the type implements Copy).
While each of these is not wrong in isolation, together they are. If we are talking about data stored on the heap that last bit is not true. Types that hold a raw pointer cannot be made Copy. Only simple types can be made Copy, ones that don't own any non direct data and as such can be stored on the stack and simply memcpyed to get a copy.
I made
Looks inside.
de-LLM readme
Claude Code committed 5 days agoAdd bench results to README
Claude Code committed 5 days agoInitial commit
Claude Code committed 5 days ago
Why does emit() take an owned E value?
Funny 😂