---
date: 2025-11-25
url: https://hackmd.io/_V9XMZslR1KgRFSQG2HLUA
---
# Libs-API Meeting 2025-11-25
###### tags: `Libs Meetings` `Minutes`
**Meeting Link**: https://meet.jit.si/rust-libs-meeting-crxoz2at8hiccp7b3ixf89qgxfymlbwr
**Attendees**: Amanieu, The 8472, Josh, David, Martin, Tomas, Chris, TC
## Agenda
- Triage
- Anything else?
## Triage
### FCPs
1 rust-lang/rfcs T-libs-api FCPs
- merge rust.tf/rfc3873 *build\-std: context* - (14 checkboxes left)
13 rust-lang/rust T-libs-api FCPs
- merge rust.tf/80437 *Tracking Issue for \`box\_into\_inner\`* - (1 checkboxes left)
- merge rust.tf/106418 *Implement \`PartialOrd\` and \`Ord\` for \`Discriminant\`* - (2 checkboxes left)
- merge rust.tf/146560 *Add the \`cpuid\` target feature* - (5 checkboxes left)
- merge rust.tf/116258 *Tracking Issue for explicit\-endian String::from\_utf16* - (1 checkboxes left)
- merge rust.tf/139087 *Fallback \`{float}\` to \`f32\` when \`f32: From\<{float}\>\` and add \`impl From\<f16\> for f32\`* - (4 checkboxes left)
- close rust.tf/136638 *warn on empty precision* - (3 checkboxes left)
- merge rust.tf/98407 *Tracking Issue for \`Exclusive\`* - (1 checkboxes left)
- merge rust.tf/145948 *Stabilize 29 RISC\-V target features (\`riscv\_ratified\_v2\`)* - (3 checkboxes left)
- merge rust.tf/146660 *Tracking issue for release notes of #146410: Iterator repeat: no infinite loop for \`last\` and \`count\`* - (0 checkboxes left)
- merge rust.tf/140808 *Implement Default for &Option* - (1 checkboxes left)
- merge rust.tf/141994 *add Iterator::contains* - (1 checkboxes left)
- merge rust.tf/135894 *Tracking Issue for \`atomic\_try\_update\`* - (3 checkboxes left)
- merge rust.tf/76314 *Tracking Issue for atomic\_from\_mut* - (2 checkboxes left)
[joshtriplett (4)](https://rfcbot.rs/fcp/joshtriplett), [traviscross (1)](https://rfcbot.rs/fcp/traviscross), [jtgeibel (1)](https://rfcbot.rs/fcp/jtgeibel), [estebank (1)](https://rfcbot.rs/fcp/estebank), [Amanieu (3)](https://rfcbot.rs/fcp/Amanieu), [the8472 (6)](https://rfcbot.rs/fcp/the8472), [cjgillot (1)](https://rfcbot.rs/fcp/cjgillot), [dtolnay (3)](https://rfcbot.rs/fcp/dtolnay), [matthewjasper (1)](https://rfcbot.rs/fcp/matthewjasper), [0xPoe (1)](https://rfcbot.rs/fcp/0xPoe), [LawnGnome (1)](https://rfcbot.rs/fcp/LawnGnome), [scottmcm (3)](https://rfcbot.rs/fcp/scottmcm), [nagisa (1)](https://rfcbot.rs/fcp/nagisa), [BurntSushi (7)](https://rfcbot.rs/fcp/BurntSushi), [nikomatsakis (2)](https://rfcbot.rs/fcp/nikomatsakis), [jackh726 (1)](https://rfcbot.rs/fcp/jackh726), [eth3lbert (1)](https://rfcbot.rs/fcp/eth3lbert), [Eh2406 (1)](https://rfcbot.rs/fcp/Eh2406), [mdtro (1)](https://rfcbot.rs/fcp/mdtro), [SparrowLii (1)](https://rfcbot.rs/fcp/SparrowLii)
### (nominated) rust.tf/100450 *Tracking Issue for \`Iterator::array\_chunks\`*
(... Tomas joined later, had another meeting)
The 8472: If you do next_chunk, you want to guarantee the size of the array so you can do vectorization. You don't want the dynamically sized chunk. You could pass in an UnInit and initialize the reference out.
Amanieu: If we had streaming iterators, would that help?
The 8472: For stuff that has contiguous memory where you have something you need to copy you can't do that. You'd need out pointers.
Amanieu: The default impl could return a reference to its buffer but a specialization for slices could ??. But we can't do that for the Iterators currently because of lifetimes.
The 8472: That's why I meant you need out pointers.
Josh: You wouldn't necessarily need a temporary buffer. IF you had a streaming/lending iterator then it's easy to build the version of chunks that returns an iterator. And you could imagine doing something like "collect this into an array".
The 8472: Then we'd need another trait that would be fixed size that guarantees there are that many iterators or blow up.
Josh: Or you'd return Some and if there's fewer than the number, return None
The 8472: Having that in an `Option` is part of the problem
Josh: having `Option<FixedSizeArray>` the compiler wouldn't be able to optimize it away
The 8472: At least not reliably enough to get into vectorization in interesting cases.
The 8472: That means we can't make the type we tell LLVM to be just a bunch of `u8`s a general type.
Josh: Is the primary usecase of `array_chunks` to vectorize them?
The 8472: We went form array_chunkss to next_chunks because array_chunks is implemented via next_chunks. But yes, it's mainly for vectorization.
Josh: I haven't been thinking of this in the terms of doing vectorization yet.
Amanieu: I've been thinking of changing the calling convention for Option and Result in return types
The 8472: Passing them separately?
Amanieu: Yes, two separate places in MIR so you can pass the Ok variant. But I don't know how to do that generically.
The 8472: That would be awesome. It'd probably help with next_chunk.
Josh: A separate place for the enum variant?
Amanieu: Yes.
Josh: We could potentially return `Option` via flags.
Amanieu: ...No.
Josh: (We should take that offline, it's a tangent.)
Amanieu: What's the next step
The 8472: Some optimization for the next_chunk. If we want to keep the current signature, we'd need internal compiler optimization.
The 8472: `array_chunks` also retursns `Option<[]>` so it has the same issue. `TryFold` with it's control flow and continue might have an optimization problem.
Amanieu: But there isn't much we can do on the libs side.
The 8472: People who write vectorized code may be okay with uninit stuff.
Amanieu: Basically, you want the array to be returned via outpointer while the `Option` part would be returned separately.
The 8472: The Rust for Linux people were talking about an `is_initialized` type of thing
https://rust-lang.zulipchat.com/#narrow/channel/528918-t-lang.2Fin-place-init/topic/In-place.20initialization.20via.20outptrs/with/539083643
Amanieu: The 8472, do you want to reply your concerns? Definitely `next_chunks` needs to be stabilized first.
### (nominated) rust.tf/148941 *stabilize \`Peekable::next\_if\_map\` (\`#!\[feature(peekable\_next\_if\_map)\]\`)*
Josh: The reason they want the `map` combined with `next_if` is whatever transformations they're doing on the item is something they do inside the function and they can't do afterwards... no, they're returning the `I::Item`.
Josh: You could have something borrowed from the original, possibly take it and transfer it into an owned type or otherwise leave it borrowed.
Amanieu: Yes.
Amanieu: There were two variants of this API. One that takes it by reference and one that takes it by value.
Josh: `next_if_map` takes a closure that returns a `Result<R, I::Item>` and I think it should be an `Option<R>`. How they use it implies it should be `Option<R>`.
Amanieu: Yes, this is listed as `Result`. What's wrong with the signature?
Josh: They're returning Result instead of Option. Based on how they use it. The closure should be `Option<R>`
David: If the closure returns `Option<R>` the items will be peeked no matter what.
Josh: If return `None` the item won't be peeked.
Amanieu: The original ACP used this as the
Josh: If you're going to take the item by value then the error case needs to return the item by value.
Amanieu: We've chaned it to take it by value and return the Result so you can put it back.
Josh: I see the advantage, but their ACP example would make it much more complicated to use.
Amanieu: Given that, are we proposing to go back to the original API for ease of use?
David: We talked about next_unpeek/peek_slot more directly. That would make this uncessary.
Josh: So peek_slot would give you a type that would behave similarly to HashMap's Entry? If so then this would indeed be unnecessary, maybe as a convenience.
Amanieu: Someone tried to implemnet next_unpeek but got stuck because the API doesn't work.
https://github.com/rust-lang/libs-team/issues/557
(everyone looks at next_unpeek)
Josh: The same usecase there as `next_if_map` showed.
Amanieu: I think in the case of `next_unpeek` it needs to consume the thing that's been unpeeked.
Amanieu: I think the one we have today (`next_if_map`) basically supersedes the unpeek stuff at least for the common usecases. And I think that's good enough.
Amanieu: There is an issue that it's only accessible in the closure.
Josh: Unless it's `Copy`.
Amanieu: If it's `Copy`, then the version that takes an option of a reference is superior.
Josh: I can see usecases for both.
The 8472: We did explicitly asked for the owned version in the ACP.
Amanieu: I think the case of the parser using peek may be the wrong tool.
Josh: That's just implementing `Peekable` outside of `Peekable`
Amanieu: Yeah but with more control.
Josh: We could give you that control in `Peekable`
Amanieu: I'm inclined to switch to the reference version since it's better for common cases of copy types.
Josh: +1
The 8472: The examples cited in the original ACP were so complex so you end up with multiline matches so you don't get much from the shortening approach.
Josh: What was the example in the original ACP?
Josh: The unpeek API still works for the generic case because you can take it out, look at it and then put it back.
Josh: IIRC, part of the problem with next_unpeek API was design concerns: on one hand you have a footgun if you don't have it bakc. On the other hand you have to fiddle with it to match it if you have the PeekSlot Entry-like mechanism. Still seems worth it though.
Amanieu: The original issue was: what if you put something back on an iterator that's already exhausted.
Josh: Then it becomes unexhausted?
The 8472: Then you're violating Fused.
Josh: And Peekable implements FusedIterator.
Josh: Technically that only means you can't put something back after you've seen the `None` after it. I think it's already the thing you shouldn't put a thing back after calling next.
The 8472: But if you have a generic Peek slot you can do that
Josh: IIUIC, FusedIterator isn't an unsafe trait in terms of you can't rely on it in unsafe code. So we can say you shouldn't
The 8472: That still doesn't mean you can allow correctness guarantees.
David: That's not a correctness guarantee. I can mem::swap the iterator too.
Josh: We could just define FusedIterator and explicitly say: "if you only have an immutable reference to the iterator, this property holds. If you have a mutable reference then you can cause issues. You're allowed to do that but you shouldn't."
David: That's my preference.
The 8472: Having a mutable reference doesn't necessarily mean you can swap it out. You must have a replacement and you may not be able to construct a replacement. Just because you handed a `&mut` to a third party code doesn't mean they can invalidate the FusedIterator
Josh: But then what are we buying by trying to enforce that?
The 8472: It does seem iffy to have a stdlib type with specific properties that then allows you to break that with other standard library types.
Josh: With the Peek slot approach, we should be able to maintain state that would prevet you form being able to put something back once it's done. We can keep that state in the Peek slot type.
The 8472: The Peekable implementation itself doesn't know the state of the inner iterator.
Amanieu: If you have a peekable iterator that's freshly exhausted and you call Peek many times, you must only return None from the underlying iterator once. Even if you peek many times. Otherwise you'd be calling `.next()` on the underlying iterator every time you'd call `.peek()`.
The 8472: Is the concern performance?
Amanieu: It's correctness. If you have a non-Fused iterator, if you called `.peek()` twice then it could return different values.
The 8472: I see, it's part of the API.
Josh: So we currently have peek_mut which returns `Option<&mut ..>` that can change what the item is, but we can't change whether there is an item to peek.
Amanieu: If you remove soemthing from the Peek slot, does that mean that the next return type will be `None` and exhaust the iterator?
Josh: I'm suggesting you'd not set the next item to None. I'm saying it could return the next item of the iterator. We could provide a return type that prevents you from doing the thing we don't want you to do.
The 8472: Which case does it prevent you fom doing?
Josh: peek_mut doesn't let you take the item from the iterator out.
The 8472: Is'nt that just `.next()`?
Josh: `next` doesn't allow you to *not* take the thing.
The 8472: You can call `peek` and then `next`.
Amanieu: I still people should just do this manually.
Josh: I think this is the job of `Peekable` to let you do this thing. This is a hard problem but it's our hard problem to solve.
Amanieu: let me check what itertools does.
Josh: They have a `PeekingNext`, an abstraction over `Peekable` iterators. Sometimes they have a native ability to peak without wrapping it around with a Peekable.
Amanieu: But that's not necessarily something you can unpeek.
Josh: And that's not a requirement we're looking at her. Just something itertools can do.
The 8472: They also have a PutBack
Josh: That's a concrete iterator adapter. It allows you to always put things back.
Josh: This seems like a case study of letting people just put things back.
Amanieu: PutBack doesn't allow you to peek.
Josh: But PeekingNext is implemented for PutBack. So technically PutBack is essentially Peekable.
Amanieu: PeekingNext is next_if
Josh: It doesn't implement FusedIterator
Josh: This is roughly what we should try to ship in
Amanieu: I'm looking at the implementation of PeekingNext. This will fetch from the inner iterator multiple times with `peeking_next`. Which I'm not sure it's exactly correct.
Josh: What do you mean? If you have an element currently peeked, it will give you that one and not call next.
Amanieu: If you peek while the iterator is exhausted, each peek will call `.next()` on the iterator.
Josh: That seems fine.
The 8472: IT's fine because it's not promising to be Fused.
Josh: That would be fine even if it was promising to be Fused if the underlying iterator was Fused
The 8472: I think the Peek API promises that if the iteration is over, None is returned.
Josh: It promises it even if the underlying iterator is not Fused?
Amanieu: I think the main thing is calling `.peek()` twice will return the same value
Josh: That only happens if you call it once, you get None, then call it again and the underlying iterator returns
Amanieu+The 8472: Yes.
Josh: :shrug:?
Amanieu: Could we unconditionally Fuse the iterator?
Amanieu: Peek only promises to be fused only if the inner iterator is fused.
Josh: We could do it internally. We can call `.fuse()` on the inner iterator
Amanieu: I'm not sure it's correct though. If `peek` promises to always call the next item from the iterator then you'd Fused would break that promise
Amanieu: Is anyone actually relying on unfused iterators
The 8472: No idea. But considering we have dedicated iterators, documentation and these are core adaptors we shouldn't ignore the properties?
Josh: Leaving that aside, it seems straightforward for us to maintain the property. Suppose PeekSlot is a type with methods similar to Entry. We could say "if the underlying iterator has returned None, PeekSlot will not let you put something back; and if it hasn''t returned None it will let you put something back"
The 8472: put_back is more general because it doesn't have the restricttio.n
Josh: true.
Josh: Alternatively, we could say FusedIterator is best effort and we try to maintain the property, but it's an automation property and a semi-correctness. WE can say "if you put something back on empty iterator you might break expectations of fused iterators"
The 8472: We could make the PutBack type
Josh: It's a mild annoyance to have to remember to put it back. But that's fine.
Amanieu: The reference-taking version -- if you don't want to remember to put the thing back, use that.
Josh: Sure.
Josh: The main reason in having a mild value in PeekSlot is: if you want to do something like a match. Today you'd call Peek, look at the item with a match, you'd call next if you want it. You'd write `.peek().next().expect()`. If I have a PeekSlot you'd have a type-level guarantee that "I've peeked at the thing, I looked at the thing and if I ask `peek_full_slot` I will unconditionally get the item"
The 8472: But then you won't be able to put it back
Josh: I think you don't necessarily need to put things back. The main rationale for ??. IT seems like the PeekSlot API that lets you look at the thing but if you want to own it you have to take it seems like it'll work fine for a lot of usecases. Even usecases that would use `next_if_map`.
Josh: Do we want to add `next_if_map` in a borrowing version that returns `Option`? That seems useful in a bunch of usecases.
Amanieu: Yes, can we agree on that?
Josh: And I'd say we'd be interested in the owning design but we didn't get to that yet. If someone's interested they should get in touch with us.
The 8472: Are we suggesting to go with Option or both?
Amanieu: for `next_if_map` the Option one for now.
TC: Did I understand that there wasn't anything you can't do with the owned version, it's just more convenient?
Josh: There's nothing you can't do with the owned version but the ergonomics suck for the common case.
The 8472: It's basically the difference between `filter` and `filter_map`
Josh:
`.next_if_map(|c| c.isdigit(8))`
versus
`next_if_map(|c| c.isdigit(8).ok_or(c))`
Josh: It doesn't have to be Copy. Think about `&str`. You can look at it and decide if you want to call `to_owned`
The 8472: What if you're iterating over `String`
Josh: Then you get `&String`
The 8472: Then you have to allocate.
Josh: If what you have is an `Iterator<String>` you call `next_if` instead of `next_if_map`.
The 8472: What's the usecase for mapping? Some transformation?
Josh: That's a reasonable question. The reason is that the motivating example is calling `to_digit`. You can easily call `is_digit`. But if you're calling `to_digit` then you'd call `next_if_map`. It lets you get rid of `unwrap` or `expect`
The 8472: But if you have `PathBuf` that doesn't work with references.
Josh: That's right, if you have `PathBuf` and you want to call `is_absolute` and give it to me if it is. Then there you would have to assert. And in that case it is the same underlying problem.
TC: I wrote the original summary when we changed it to the owned version. And I still feel the `map` implies you should be passing ownership into the closure just like in `filter_map`. The cases like `PathBuf` seems pretty compelling.
Josh: Is this a naming problem?
TC: I think `next_if_map` has the right name for the owned one. But for the reference-taking one the name doesn't fit.
Josh: "map" does have differnet meenigs. We have things like `ok_or` and `ok_or_else`; `then` and `then_some` where both functions have use the same word in different meaning depending on the context but map to the same name. Here as well they're both a mapping operation.
The 8472: I don't think we ever have something that gives you an item by reference and then throws it away. If you take something by reference, you map it to a value, then we throw away the old owned value.
TC: It would feel oddly restrictive to ship the reference one and not the owned one. If we're shipping one, it makes sense to ship the owned one.
Josh: Someone showed up with an ACP, wanting to solve a usecase. And if we generalize it enough so that it's not a great use case, then we shouldn't ask the person to come up with a new ACP for that original usecase.
Josh: We could say that we have a version of this that only operates on `Item: Copy` and then it gives the thing by value and returns an `Option`.
The 8472: That sounds okay. We keep it, you get a copy.
Josh: This feels we're bumping into the failing of a lot of people wanting auto-`Deref` for `Copy` types. If arrays in general weren't `copy`, it would be okay if there wasn't much difference between a reference to a `Copy` type and a `Copy` type.
The 8472: With the PeekSlot you could take it by reference, take the value out and discard the old value.
Josh: PeekSlot could own the value and let you get it by reference, mapping etc.
The 8472: And for `char` you can just get the reference and say "ok, I'm done with it, throw it away"
Josh: And with `PeekSlot` we can structurally guarantee that you have an item and therefore you don't have to check more than once that you have an item.
***
Josh: I want to go back to Amanieu's point. Can we agree that we want the thing that's useful for the original usecase that borrows and returns an Option.
Amanieu: It's related. We can only really do the referenced one only if we have solid case for transfering ownership. I guess next_if is the way?
The 8472: But then you're back with separating the check from the transfer.
Josh: In that scenario, how usable is the alternative? It's workable.
TC: Can we keep `next_if_map` as it is and add `next_if_map_ref`?
Amanieu: I was thinking the same thing.
Josh: Which ones we want to offer. Suppose you have a PathBuf. If you use next_if_map on a pathbuf, you can't just call ok_or on the resulting Option. The compiler won't let you call ok_or if it's not Copy.
Josh: If you have a `to_secure_path` which returns
The 8472: It would be an error case to return the original.
Josh: You're saying if you had an `Option<SecurePathBuf>` it should return a `Result<SecurePathBuf, PathBuf>`. That makes sense.
The 8472: Yes.
Josh: That's a pretty compelling argument.
The 8472: It's kind of the "parse don't validate argument" and the error case lets you do whatever you want with the value that failed parsing.
Josh: In that case we can come name things.
Amanieu: There's no reason why the reference can't be an immutable reference.
Josh: you're right. Might as well be.
TC: `next_if_map_mut` to distinguish it from the owned version.
Josh: I'm trying to find examples in the standard library where we have all ref, mut and owned. Or ref and owned or mut and owned and how we distinguish those cases.
The 8472: `iter`, `iter_mut` and `into_iter`.
Josh: That's a good example. But that's if you're consuming the whole thing. Which we aren't here.
The 8472: `to_` and `into` are the common ways to do this.
Josh: `next_if_map_into`?
The 8472: Something like that.
TC: `into` to me suggests you're consuming the `self` type.
Josh: This is the common problem of: are we talking about self or
TC: for `Pin::into_ref`.
Josh: Do we have a consensus that we want to offer the own and borrow cases for different usecases?
The 8472: What about the earlier suggestion to use `Copy`? That would also work for the `char` case. So which one is better, `Copy` or reference?
Josh: I could buy into `next_if_map` and `next_if_map_copy`.
The 8472: I think that fits better in our overall iterator approach.
Josh: `next_if_map_copy` will literally be `next_if_map` with an `ok_or` built in.
Amanieu: What's wrong with the reference version?
The 8472: You'd need deref?
Josh: If we passed in a mutable reference, we'd be fine. Wort case you'd have to put `*` in front of it.
The 8472: Copy would prevent that.
Josh: Either one seems defensible and fine for different usecases.
The 8472: I slightly prefer the `Copy` version but I could live with the reference version.
Josh: Both seem fine to me.
The 8472: The reference is slightly more general.
Josh: Yes.
The 8472: Yeah, ok.
Josh: Would it make sense to do the mutable reference?
The 8472: We have started with the immutable version and then added `&mut` later on, like `retain_mut`. Is theres any reason to deny the mutable access?
Josh: Can you write `|&x|` in the closure and have the `&mut` automatically pattern match that. If you can, that seems fine.
Josh: *checks in the playground*
Josh: It doesn't work. The primary reason for not passing `&mut T` is that you can't pass a closure that expects `&T`. You have to explicitly
TC: That's one of the things we were going to fix with the expanded match ergonomics thing.
Josh: I think we may handle that case and it may be closure ergonomics that might be the problems
The 8472: Would that also work for passing function references (like `filter(Foo::bar)`)
TC: I feel we could fix this on the lang side.
Josh: You're not introducing a `mut` where it never was. So there's no hazard there.
TC: Plus you're downgrading it.
Josh: Yes. It doesn't seem dangerous because you're only making it less mutable. So yes, that seems like a reasonable ergonomic improvement. And if we do, I see no reason not to have `next_if_map_mut`
TC: And if we fail to do this on the lang side, we can always add `next_if_map_ref`.
Josh: Now we're just down to naming: do we want `next_if_map` and `next_if_map_mut`, or do we want `next_if_map_owned` and `next_if_map`?
TC: Let's pick `next_if_map` for the owned one and `next_if_map_mut` for the reference one.
Josh: I propose we explicitly say we talked them through, that we want both and that we need to have some sensible names. And we can have the naming conversation some other time.
TC: That sounds fine.
The 8472: Should we mention PeekSlot or is that too confusing?
Josh: We can say that we're open to that kind of API but we're not there yet.
Josh: I'll write this up.
### (nominated) rust.tf/149238 *float::clamp: make current treatment of signed zeros explicit*
Amanieu: it clarifies that `-0.0` and `+0.0` are considered equal. Panics on `NaN`. I think it doesn't specify whether we return `-0.0` or `+0.0` in this case.
Amanieu: The implementation doesn't use the `float::min` / `float::max`
Chris: Is there a more general documentation on how float behavies?
Amanieu: The IEEE one
Chris: Can we reference that?
Amanieu: It doesn't have `clamp`
Amanieu: This implementation can prevent it being efficiently implemented on some CPUs. And it guarantees that if `self` is `NaN`, the `NaN` payload is propagated. Which means LLVM can't turn them into a set of `min` and `max` instructions.
The 8472: Can we change it?
Amanieu: It's stable.
The 8472: But it looks like we're not guaranteeing `NaN` properties.
Amanieu: At the moment this treats `-0.0` and `+0.0` as equal. But if we use `min` and `max` functions on floats, those do treat `-0.0 < +0.0`
The 8472: Where would this make a difference?
The 8472: this code:
```rust
#![feature(float_minimum_maximum)]
fn main() {
dbg!((-0.0_f32).min(0.0).max(0.0));
dbg!((-0.0_f32).minimum(0.0).maximum(0.0));
dbg!((-0.0_f32).clamp(0.0, 0.0));
}
```
results in this output:
```
[src/main.rs:3:5] (-0.0_f32).min(0.0).max(0.0) = 0.0
[src/main.rs:4:5] (-0.0_f32).minimum(0.0).maximum(0.0) = 0.0
[src/main.rs:5:5] (-0.0_f32).clamp(0.0, 0.0) = -0.0
```
The 8472: The `-0.0` is treated as equal in both cases because if it were smaller, it would not be in range.
Amanieu: Yes. Today it's treated as equal because we use normal comparisons instead of the intrinsics.
The 8472: I have `min` and `max` calls there. Aren't they the same as the intrinsics?
Amanieu: That should be. Can you run this with optimizations?
The 8472: Same results. We also have these `minimum`/`maximum` (unstable) methods. Do they make a difference?
The 8472: No, same results.
Amanieu: The docs for `minimum`/`maximum` specifically say that `-0.0` is greater than `+0.0`
The 8472: Oh, is this a precedence issue?
The 8472: Okay, updated, only clamp is the outlier.
Amanieu: min/max still gives me `-0.0`
The 8472: What are you testing?
Amanieu: I copied your code and just added the brackets for precedence.
Amanieu: and if I switch to release mode, the behaviour is different
:tada:
\o/
(everybody cheers)
Amanieu: I think this needs more investigation.
The 8472: The `min` and `max` are allowed to non-deterministically return either behaviour. So it's allowed.
Amanieu: So if we use `min` and `max` it gives you non-deterministic behaviour. Which allows you to be more efficient on x86. I think this is fine. I'd be in favour of accepting this.
The 8472: With Ralf's addition we should still be able to change the criteria.
Amanieu: We should be more explicit in the description. I'll reply.
### (new change proposal) rust.tf/libs702 *ACP: Add \`wake\_fn\` to \`alloc::task\`*
Josh: https://github.com/rust-lang/libs-team/issues/647 seems related because `Waker::from_fn_ptr` can be more efficient. `wake_fn` is safe but requires actually storing the thing. But it does seem useful.
The 8472: If it's a non-capturing closure, can it be optimised down to the same thing?
Josh: Possibly? That would be nice. And that might be how people typically implement an async runtime -- they don't look why they were woken just that they were.
The 8472: It was added 5 hours ago.
Josh: Let's add the `I-async-nominated` and give them chance to reply.
### (new change proposal) rust.tf/libs701 *Disabling allocations in \`pre\_exec\` (and signal handlers)*
Amanieu: In some context, you're only allowed async-signal-safe functions. That means no allocations. It always matters in signal handlers and in pre-exec it only matters for async.
Amanieu: I think it boils down to avoiding pre-exec like the plague?
The 8472: This mentions ub-checks. We can try to do best effort?
Amanieu: ub-checks are designed to be optimized away in the release mode. These need to be inline functions.
The 8472: Are you sure? It works for OwnedFd sanity checks. E.g. you're not closing an already closed OwnedFd.
Amanieu: I'm not too concerned about OwnedFd. I'm concerned about putting anything on the allocator fast path.
Josh: They're saying you could use debug_assert! but that still doesn't help you if you aren't in debug mode
The 8472: Do they have a PR we can look at?
Amanieu: This seems too much work. I understand pre-exec is hard to work with.
Chris: Could we just have a lint that could be silenced?
Amanieu: No. You'd need some way of differentiating which functions are async-signal-safe and which ones aren't.
Josh: In a language with a capability system, this would be marked as not having this capability here. But that's not Rust.
Josh: Our actual answer is "fork is awful, there are lots of reasons we might want to make it more reasonable. But the proposal as described is only solving allocator, but it would have the implied property that anything that's not async-signal-safe must check that it's not async-signal-check and that's backwards".
The 8472: I don't think you'd have to check everything, just the most common problems.
Josh: I'm just saying that everyone using async-signal-safe should check rather than everyone else.
Josh: I think fundamentally that's the reason why we killed safe before_exec and added `pre_exec`.
The 8472: The ub-check should help you with unsafe code
Chris: For this specific usecase can we document this?
Amanieu: It specifically calls out `Error::new`. It is documented. If you need it, call out to libc directly.
Josh: Or alternatively, if you're using pre_exec don't be multithreaded.
The 8472: I think Chrome spawns a helper process which then does the forking and handle all these issues.
Josh: The main reason is that Chrome processes are expected to be huge.
The 8472: And it's also this added benefit.
Josh: We can say there are two options: either you be very careful or you can be single threaded (and one way to do that is have a single-threaded helper process that you can fork)
Josh: If we didn't expose this publicly as an API and only use it internally as a ub-check with, then I see no reason not to. But not exposing this as a standard library API.
Amanieu: Yes.
Amanieu: If it's a debug check built into the default allocator it's fine if the performance overhead is small enough.
Josh: Agreed. We're not opposed to an internal-only version with no public API if it doesn't have a substantial performance hit.
Amanieu: It really boils down to "only use libc functions". At least the ones that are async-signal-safe are documented.
### (new change proposal) rust.tf/libs700 *Mapped Arc and UniqueArc*
Amanieu: There are two wasy this could be implemented. Depends on whether we want the Utype to be kept in Mapped Arc. For MapMutexGuard in parking lot I designed it to perform type erasure. Only the `T` for the MappedType is kept, not the original type.
The 8472: For Arc that doesn't work if you only keep the mapped version if the original is gone and the original ref count is set to zero?
Amanieu: It does. Custom vtable.
Amanieu: Is that something we'd be more interested in? It'd need to be a bit more than a custom vtable but it should be simple to implement.
Amanieu: Alternative: leave the `U` parameter in, if you want type erasure, make it `dyn`
Josh: There are things like DynAny but you need to implement Any. We don't have a complete generic that allows you to implement it on any type without declaring it.
The 8472: In the new hierarchy, would it be DynMetaSized?
Amanieu: DynSized, not MetaSized.
...
Amanieu: Sorry, you should be MetaSized
Josh: We talked about ArcRef or similar to keep the Arc references separate from the things they're pointing to.
Amanieu: Yes, that's the same thing.
Josh: Don't we have a proposal for that?
Amanieu: There's a crate called triomphe that has a lot of types with Arc.
Josh: There's an RFC for Field Projection
Amanieu: Yes, but on the other hand didn't we just add ArcMutexGuard?
Josh: We should have ArcMutexGuard. But ArcRef is basically mapped Arc. It's the same underlying problem.
Amanieu: With MapMutexGuard the original type in the mutex can be unsized
Amanieu: Do we want the original type be part of the signature or do we want type erasure?
Amanieu: If you need type erasure, you need two pointers.
Josh: If you want a type-erased version, you have to keep something around at runtime to tells you how to drop it. Effectively a `dyn Drop`.
The 8472: Could we implement both? An erased and a concrete T?
Josh: Could we? Yes. Should we?
Josh: MappedMutexGuard seems to be erased.
The 8472: Because it's only the guard.
Amanieu: It only has a pointer to the raw mutex. It doesn't need a vtable.
Josh: Ah, MappedMutexGuard owns its value but it's not the only pointer to it.
The 8472: We have `Box` and `ThinBox` and people writing complex data structures seem to like their thin pointers. I assume they'd also have a lot of Arcs floating around.
Josh: So you could have a `ThinArc` where the arc would have an indirect reference. Have a `ThinArcRef` effectively. And `ThinArcRef` would keep around the reference.
The 8472: It's kind of backwards. In the ThinBox we keeep the erased information and ThinArc we'd keep the information in the type system.
Josh: The advantage of the type erased version is that it looks just like Arc. The advantage of the other version is that it can be more efficient, but it does that by monomorphising individual functions which take one. So you'll end up with multiple copies of funcitons that work on ArcRef that only differ in how they drop the original type.
Amanieu: Yes.
Josh: I can easily imagine people who would have taken `Arc<MyConcreteType>` and wouldn't be generic at all.
Amanieu: ??
Josh: I'm assuming you don't re-call that function every time you need it.
The 8472: Isn't that basically the projection stuff?
Josh: Yes.
Josh: I could see the value in having both of these. But the common case is "I only want to talk about the type I have and not the parent type". To the extend you're trying to build more efficient code, you're also doing borrowing and not an Arc. We could add the thin version later on. But that's more specialized and for now we should only have an ArcRef with T that is type-erased.
Josh: I'd propose that we write: "we're sure we're going to want somethnig like this. Theer's a bunch of work that's happening in field projections that want this, cc Alice and Benno, then say coordinate so we have a single concrete proposal and make sure we don't have duplication here"
The 8472: It also talk weak pointers.
Amanieu: Weak pointers are not upgradeable. They introduce mapped unique pointers. A mapped unique pointer cannot be upgraded. You can't convert MappedUniqueArc into a MappedArc. That would break too many things I think.
### (new change proposal) rust.tf/libs699 *Bring \`hashbrown::Equivalent\` into std*
### (new change proposal) rust.tf/libs698 *Stabilize trait \`ZeroablePrimitive\`*
### (new change proposal) rust.tf/libs691 *\`std::io::Read\` provides byte\-order reading trait*
### (new change proposal) rust.tf/libs688 *Initial state once cell value*
### (new change proposal) rust.tf/libs659 *Generalize ExactSizeIterator to QuantifiedIterator*
### (new change proposal) rust.tf/libs656 *implement Default for more iterators*
### (new change proposal) rust.tf/libs651 *ACP: Add API to write formatted data directly into a \`Vec\<u8\>\`*
### (stalled change proposal) rust.tf/libs296 *ACP: Designing an alternative \`FromStr\`*
### (stalled change proposal) rust.tf/libs379 *Combine, an iterator adapter which statefully maps multiple input iterations to a single output iteration*
### (stalled change proposal) rust.tf/libs347 *Context reactor hook*
### (stalled change proposal) rust.tf/libs520 *Add out of the box support for mapping custom error types that implement \`std::error::Error\` to \`Box\<dyn Error\>\`*
### (stalled change proposal) rust.tf/libs525 *Vec::try\_remove*
### (stalled change proposal) rust.tf/libs298 *Constructive/Destructive Interference Size Padding*
### (stalled change proposal) rust.tf/libs131 *Add \`std::fs::rename\_noreplace\`*
### (stalled change proposal) rust.tf/libs501 *ACP: Add floating point representation conversions*
### (stalled change proposal) rust.tf/libs287 *ACP: Add \`FromByteStr\` trait with blanket impl \`FromStr\`*
### (stalled change proposal) rust.tf/libs452 *ACP: Implement \`TryFromIterator\<T\>\` trait to compliment \`FromIterator\<T\>\` trait.*
_Generated by [fully-automatic-rust-libs-team-triage-meeting-agenda-generator](https://github.com/rust-lang/libs-team/tree/main/tools/agenda-generator)_