Try  HackMD Logo HackMD

Libs-API Meeting 2025-08-05

tags: Libs Meetings Minutes

Meeting Link: https://meet.jit.si/rust-libs-meeting-crxoz2at8hiccp7b3ixf89qgxfymlbwr
Attendees: Josh, Amanieu, Chris Denton, Mara, The 8472, David, scottmcm, TC

Agenda

  • Triage
  • Anything else?

Triage

FCPs

15 rust-lang/rust T-libs-api FCPs

  • merge rust.tf/80437 Tracking Issue for `box_into_inner` - (1 checkboxes left)
  • merge rust.tf/140808 Implement Default for &Option - (3 checkboxes left)
  • merge rust.tf/133289 Tracking Issue for `const_array_each_ref` - (3 checkboxes left)
  • merge rust.tf/143191 Stabilize `rwlock_downgrade` library feature - (3 checkboxes left)
  • merge rust.tf/106418 Implement `PartialOrd` and `Ord` for `Discriminant` - (2 checkboxes left)
  • merge rust.tf/65816 Tracking issue for `vec_into_raw_parts` - (3 checkboxes left)
  • merge rust.tf/132968 Tracking Issue for `NonZero<u*>::div_ceil` - (3 checkboxes left)
  • merge rust.tf/139087 Fallback `{float}` to `f32` when `f32: From<{float}>` and add `impl From<f16> for f32` - (5 checkboxes left)
  • merge rust.tf/129333 Tracking Issue for `lazy_get` - (3 checkboxes left)
  • merge rust.tf/127213 Tracking Issue for AVX512_FP16 intrinsics - (3 checkboxes left)
  • merge rust.tf/136306 Tracking Issue for NEON fp16 intrinsics - (3 checkboxes left)
  • merge rust.tf/141994 add Iterator::contains - (3 checkboxes left)
  • merge rust.tf/144494 Partial-stabilize the basics from `bigint_helper_methods` - (3 checkboxes left)
  • merge rust.tf/144091 Stabilize `new_zeroed_alloc` - (3 checkboxes left)
  • merge rust.tf/63569 * Tracking issue for `#![feature(maybe_uninit_slice)]`* - (3 checkboxes left)

jackh726 (1), dtolnay (1), scottmcm (1), Amanieu (2), BurntSushi (13), m-ou-se (13), joshtriplett (11), nikomatsakis (2)

(nominated) rust.tf/93743 Tracking Issue for str::{floor, ceil}_char_boundary

Chris: There was some discussion about a different API

Josh: That would be a completely different function

Chris: The argument was you could just use split instead of indexing

The 8472: With splitting we can internally optimise it to use unsafe if necessary to have an efficient, guaranteed safe API. But I'm not sure how important it is. We could check whether this optimizes or not.

Josh: If someone wants to propose the split APIs, more power to them. But people are also asking for {floor}_char_boundary. We should go through the FCP to stabilize those and separately do the split APIs

Chris: I'd be happy with that.

Josh: All the people asking for a split API said I'd like to do this with a split API and all their justifications for the char boundary is that it could be done with a split API.

Amanieu: I don't feel strongly about either.

Josh: Does anyone feel strongly enough about not doing char_boundary to stop the FCP and do something else?

[silence]

Josh: I can post a comment to that effect.

The 8472: I don't see any panic path.

Josh: ceil has a panic but floor doesn't. ceil can discover you have an incomplete UTF-8 character hanging off of the string.

The 8472: We can say it's UB and do an unchecked thing

Josh: I think we have the option of doing either. Panic or assume it's there for optimization.

Amanieu: If it's UB I'd assume we'd only do it in debug builds

(nominated) rust.tf/116258 Tracking Issue for explicit-endian String::from_utf16

Amanieu: This is a request for stabilization.

Josh: Seems fine. Chris?

Chris: This is less of an issue for Windows because we can always assume little endian. But I'm happy with it

Mara: There's some discussion on the error type. The error type is currently wrong.

Amanieu: Is there anything preventing us from adding new variance to ??

Josh: It's fields are private.

Amanieu: it doesn't have any fields

Josh: So it's trivial to introduce variance

Amanieu: It would no longer be a ZST but honestly so what

Mara: The ZST is useful if you return a Result

Josh: Why don't we start an FCP and add a concern to fix the error type and observe that it could be done in one of the couple of ways and submit a PR.

Mara: I'm also happy to just changing the error message to only "invalid utf-16".

Josh: I can start an FCP as well as make a note about fixing the error.

(nominated) rust.tf/140267 implement continue_ok and break_ok for ControlFlow

David: This is exactly on the fence of things we should do and shouldn't do. Someone went looking for a method they expected to exist. It didn't exist so they opened a PR to do it. But it's not clear that this method is useful enough to be in the API

David: A relatively small number of people will want this and they will expect it to exist

Josh: A relatively small number of people will use ControlFlow. What proportion of those will need this method?

TC: Checking where we are procedurally, the ACP for this was accepted and we're not up for stabilization yet. We're checking midway whether we still want this?

David: I think it's an instructive example to discuss.

David: To reply to Josh's comment, there are two rival ways to frame the decisinon: relatively niche types should have consistent APIs but on the other hand they should have a consistent level of though to put into it

Josh: I wasn't suggesting it's a problem because it's a niche type. More to express whether it's a relatively niche people within that niche or most people?

Scott: Part of the advantage of using ControlFlow is where Ok is not Continue and you want the ok to be short-circuit. The place that came to mind would be where it's different from Result. But I don't know whether we'd want a method that does the opposite of what Result does.

One of the benefits of ControlFlow is that it's non-oppinionated way of doing this

David: I think the design is consistent: it asks you to say which of the cases is okay. It doesn't prefer one side of the flow.

The 8472: Both types are try. Would it make sense to generalise this throught the Try trait to define which one is whicho ne? try_left / try_right?

TC: Try doesn't really have a "left" and "right" in that sense. It has the "main" and "residual" branch.

Scott: I think the continue/ok could be phrased that way but break/ok could not.

TC: To the meta point David is raising: I think there's a bit of a self-fulfiling prophecy on these types. If we say not enough people use these so we won't add methods on them, then no one will use them because they're not as useful enough. If we want people to use these types, we should make them as useful as we can.

Josh: Agreed. If we're going to add something, let's add all the pieces that should be useful as if it were a more popular type

Scott: I think that's useful TC, but the type would be useful even without those conversion methods

Scott: IF we have brake/ok and continue/ok should we also have break/err and continue/error?

David: Those are the same methods, just with different names

Scott: Why do we talk in terms of "ok" instead of "error"? But that can be a stabilization question.

Amanieu: We're happy accepting this as it is.

(nominated) rust.tf/144494 Partial-stabilize the basics from `bigint_helper_methods`

scottmcm: 🌊, I'm here in case you wanted to chat about this one more. To copy in a comment on the previous discussion,

From the notes:

carrying_mul_add seems like the more questionable one. Mainly because I've not seen many uses for it.

I actually was originally skeptical of it as well. The big thing that changed my mind is that both carries are useful in wide multiplication: after the digit multiplication, you're not only adding the carry from the previous digit, but also adding the result to the running sum that is the output. carrying_mul is enough only for wide multiplication by a digit, not wide-times-wide.

(And TBH it's nice that it makes the inputs be able to exactly cover the output range of the return type. (2^n-1) * (2^n-1) = (2^(2n) - 1) - 2(2^n - 1), so there's space for 2 carries, not just one. Even if we had pattern types there isn't a nice way to say precisely what the output range is for wrapping_mul or carrying_mul in the types.)

Amanieu: I did register a concern around the naming. Wasn't a fan of calling these carrying_mul and carrying_mul_add preferring widening_.... That perfectly describes what it's doing.

TC: Why is that better than carrying?

Amanieu: "carrying mul" is the same thing as "mul add" in the case of a multiply.

Josh: You're not proposing to change the "carrying add" name, just carrying_mul and carrying_mul_add?

Amanieu: Yes

Josh: Okay, I'm fine with either.

The 8472: Worth checking what these are called in the bignum libraries?

Amanieu: Seems most libraries in the ecosystem are using carrying_mul_add. I'm happy to withdraw my concern if everyone's happy with this.

Mara: I slightly prefer your suggestion but I don't have strong opinions.

TC: Is this just about mul add or about carrying mul as well?

Amanieu: carrying_mul as well. I'd rename that to widening_mul_add.

TC: What would you renamen carrying_mul_add to?

Amanieu: widening_mul_add_add

Amanieu: Consider what these methods look like on signed numbers. carrying_add doesn't make sense on the signed numbers at all. widening_mul_add works perfectly fine for a signed multiply. I'm not sure if the concept of a carry works on a signed multiply.

Scott: widening_mul_add_add is a weird thingto have on signed because it doesn't hit the exact range of the type. A lot of these are particularly weird for signed types without extra tthought.

Amanieu: widening_mul_add makes perfect sense for signed types.

Scott: yeah. I think widening_mul makes perfect sense on signed but the "add"s are more complicated. (In fact, all 4 combinations of signed and unsigned are reasonable for just the widening part.)

Josh: We've explicitly excluded the signed types due to the bikeshedding risks.

TC: The premise of the rename is less about focusing on the name carry and more about the arithmetics of it. The context is how you'd use these in a bignum library where these are more ??

Amanieu: yes.

David: What we're saying "carrying" is what you'd likely use this for. But there are other usecases where the name "carry" would be misleading.

Amanieu: yes.

TC: Are there other usecases? The only time I'd want this is to use it for carrying.

David: This rename of std::ops trait. Other languages would name it Plus but we wanted to name it Add because plus is also sometimes used for string concatenation.

Scott: The reason I included widening in my original proposal was a lot of people who wanted to just get the high part of the multiplication without caring about the "carry". But we can just decide to just have the widening or carrying version.

Josh: Id' happily sign off on stabilizing on either name. But I'm sympathetic to the premise of: "would anyone use it for anything other than a carry"? If anyone even for a smaller usecase would use it for something other than carrying, then we should use widening.

TC: And widening_mul_add_add?

Josh: Yeah, that's an argument in the other direction; that's an awful name.

Scott: a middle of the road proposal to have: widening_mul, widening_mul_add and carrying_mul_add? You wouldn't have carrying_mul, you'd have widening_mul_add instead. That way you'd see "mul add" as the main operation either way, and it's up to you if you want a carry with it.

The 8472: https://github.com/recmo/uint/blob/25e81ad8c6732624ce92e7d12800715e78df726c/src/algorithms/mul_redc.rs#L158

fn carrying_mul_add(lhs: u64, rhs: u64, add: u64, carry: u64) -> (u64, u64) {
    u128::muladd2(lhs, rhs, add, carry).split() 

Amanieu: anyone who would want to use these for non-bignum usecases would probably be the output type to be a wide integer type instead of pair of integers

Scott: That came up on the tracking issue, but the question is what would we do itt for 128

Amanieu: If you just want a widening multiply, what you want to do in practice is to cast the two inputs to a wider integer types and multiply those. Because widening_mul doesn't give you what you want. That may be an argument against stabilizing widening_mul. If you only want widening you want the output to be wider interger type

The 8472: Not for the hashing usecase scott mentioned.

Scott: the IRLO use that 8472 is mentioning: https://internals.rust-lang.org/t/methods-for-splitting-integers-into-their-halves/23210/7?u=scottmcm

Amanieu: That's more usecase for the carrying_mul. Widening I'd expect to return a single integer type.

The 8472: For hardware it makes sense to have them split to pieces.

Scott: FWIW I'd be perfectly happy to stabilize this without the widening part. The carrying is the main piece of this.

Josh: FWIW I wanted the widening version (returning a single value) without the carry and wished it to have.

Amanieu: Which is why we shouldn't stabilize it as it is now. Because it returns a pair of integers.

TC: Scott, does carrying_mul_add with a zero carry optimize down the same as widening_mul?

Scott: Yes, widening_mul is implemented as carrying_mul_add(0, 0) in the library.

Amanieu: Path forward: remove widening_mul and keep the rest.

Scott: there's an interesting possibility of having widening everything

Amanieu: Should we outright remove the existing widening_mul as part of this? Considering the lack of consensus. And leave the name available for a future method.

TC: Do we have a problem with widening_mul existing or just a problem with the name?

Amanieu: The method as it is is a carrying multiply which takes a carry of 0.

TC: You're taking one limb (word) in, and you're doing a multiply and you're getting two limbs out.

Scott: If you're doing this in a sequence, it's likely you'd have a variable that's set to 0 at the beginning. If you're thinking of limb you're using carrying and so it should be using the carrying form.

Amanieu: I'll reply to this one.

(nominated) rust.tf/144861 Stabilize `panic_payload_as_str` feature

Tracking issue: https://github.com/rust-lang/rust/issues/125175

Mara: FCP finished a year ago, but we never actually stabilized this. Let's just merge this?

Amanieu: There's been no additional objection since FCP, it's still valid. Seems good to me.

Mara: Will r+ the PR

Josh: Would it be worth filing an issue on clippy to have a lint about downcasting a panic payload to str or String. The users should be checking both of these by using this new method.

Mara: Sure, can file an issue for that.

(nominated) rust.tf/144870 Stabilize `path_file_prefix` feature

Amanieu: Another FCP that ended a year ago.

The 8472: That was nominated because I raised a concern because now we have a method that returns the last extension and a method that returns the basename. We don't have anything that returns the middle part. There was a proposal to return an iterator for all the componenths (basename, extension1, extension2).

Amanieu: Isn't that just String::split(".")

The 8472: Yes but this is on OsStr not String

Josh: I think the idea of having an ability to iterate over multiple extensions is a good idea. But I'm not sure that's the thing people are typically going to want. Having a full basename for this is useful. You want to go through the extensions in reverse (unpack the 'gz', then unpac the 'tar' etc.)

The 8472: But all the code examples on this method and related ones list the multi extension usecases. And we only have support for the last extension and the basename and nothing else. So the question is: can wem do better? I proposed splitting it.

Josh: The only problem is you said "instead of". I'm happy to add both of these methods. There's a reason why base name, dirname etc. are standard function in Unix system, even though they could just let you split on a path separator.

Amanieu: I'm against having an iterator. I think it's too much complexity. In practice people shoud be doing .ends_with.

Josh: The common pattern I've seen is: look at last extension, if you know how to process it, do that. Until you get to basename. But I agree we don't have a process to do that with iteration.

The 8472: If you think the method itself (just returning the basename) has enough value my concern is withdrawn.

Amanieu: Is this the same as unix basename?

Josh: Not quite. basename and dirname split at the last separator. basename of a/b/c.tar.gz gives you c.tar.gz. file_prefix gives you c.

Amanieu: I think this is fine. I'm happy to merge as is. I don't think we need additional methods.

Josh: If you have .config.toml it gives you .config.

TC: Do we want it the other way around?

Josh: I think this is what we want. Because in most cases you need to treat dotfiles specially.

The 8472: We should improve the code examples to cover this too.

Josh: I agree, showing when you do .config.toml it gives you .config would be great.

The 8472: I'll submit that doc patch.

(waiting on team) rust.tf/139087 Fallback `{float}` to `f32` when `f32: From<{float}>` and add `impl From<f16> for f32`

Amanieu: Waiting on Lang.

(waiting on team) rust.tf/144037 Rename bool::ok_or[_else] to bool::then_ok_or[_else] to avoid confusion with Option::ok_or[_else]

Amanieu: not waiting on this team, waiting on FCP.

(waiting on team) rust.tf/144330 document assumptions about `Clone` and `Eq` traits

Amanieu: Request for FCP. We never documented the fact that when we clone something we expect that the result of the clone to be equal and HashMap specifically rely on this by assuming that the cloned key has the same key (and won't rehash). I think that's reasonable.

The 8472: The documentation seems wrong though. You need to do this recursively otherwise some nested type could be violated.

Amanieu: Trie. It should probably also include Hash. And probably Ord too.

The 8472: Does BTreeMap have the same assumption?

Amanieu: I don't know for sure.

Chris: Do we need to mention the special case of float (which is not Eq itself)?

Amanieu: This is not PartialEq this is Eq.

Amanieu: I'll write up some connections and start an FCP.

(new change proposal) rust.tf/libs631 `first_set_bit` and `last_set_bit` for integer types

Josh: Do we have precedent for the use of firstand last here? It'd be nice disambugiation if we said "lowest set" and highest set. I'm not finding anything. Thoughts?

Amanieu: Yes, I think. But my objection to this proposal: the bits are 1-indexed.

(collective groan)

The 8472: we have trailing_ and leading_, which also suggests some directionality.

Josh: Those seem to be from the era of "six characters for naming should be good for everyone". I do think we should try to give a more reasonable name for this. I don't know why one-based.

Amanieu: That's what C does and using the 0-th bit as unset.

Josh: is that what people would like or was it just because they didn't have Option?

Amanieu: They didn't have Option

Josh: If we're going to handle the error case we either want to use Option or to panic. One of the other.

Amanieu: last_set_bit is equivalent to 'check i.log2()'

Amanieu: Should these be methods on NonZero?

Josh: Yes and they should return a non-Option. But should also be on i32, i64 etc? I think they should also exist on zeroable types

Amanieu: we accepted an ACP already

Josh: least-significant_one and most_significant_one

Amanieu: It's not implemented.

Josh: These are different options. They don't return index, they return the bit.

Amanieu: I'd still want most-significant-one

Josh: These did get implemented. They're not making the other request redundant. But do we want "most significant one" or "highest one"

Amanieu: Someone suggested adding doc aliases for check_ilog2 and check_trailing_zero

The 8472: Bikeshedding is also an unresolved question on the isolate_* tracking issue. So there's no precedent. So now we have a name that would let us pick a good name for both.

Amanieu: Can we consider not having these methods and just pointing to the doc aliases? check_ilog2 for highest bits and trailing_zeros fo rthe lowest bits.

Josh: trailing_zeros will give you a number of bits for a type with zero and lowest_bits would return None

Amanieu: Personally I'd like to have these available even though tehy're redundant. It's what people will look for.

Josh: I agree.

Amanieu: It makes the code a lot more readable too. check_ilog2 / trailing_zeros requires more thinking

Josh: Respond to ACP, we'de like to return an Option, we'd like to be zero based, we'd like them to use highest/lowest rather than first/last.

Josh: We should also post to the tracking issue of the isolate_* tracking issue that those are too long

TC: That sounds like a separate bikeshed.

The 8472: I disagree with first/last being ambiguous. We have leading/trailing and the leading one is the first one.

Josh: I think leading and first have different interpretation.

Josh: "first" has two obious interpretations due to history. Rather than telling people which one we mean, we should name a different one.

TC: What's the history you were referring to?

Josh: Look up the FFS and FLS on Unix. Find First Set (FFS) looks for "least significant bit".

Amanieu: Do we have consensus on highest/lowest?

Josh: I don't think we have consensus on that, but I think we agree we don't want first/last and this is one option.

Josh will respond.

Josh: Why is it that all these return u32 rather than usize or u8.

Amanieu: All of the indexing functions return u32. It's just precedent.

TC: We could combine tihs with the other ACP to get the shortest names. Then we'd have highest_one and lowest_one and isolate_highest_one and isolate_lowest_one.

Josh: Agreed. I'll take care of that. The comment should go to the tracking issue as the ACP is closed.

Amanieu: I basically agree with these with all the comments Trevor Gross made. We don't need to say "ascii". We don't need "is_ascii" if the method takes Self.

The 8472: The downside is if it doesn't take a reference you can't pass it to filter methods because they typically pass by references.

Amanieu: Yeah, but I don't think that's what we should base this on.

The 8472: Yes, the filter issue is more of a language limitation but it's still a limitation.

Amanieu: Sure.

Amanieu: I'll accept this.

(new change proposal) rust.tf/libs629 OnDrop: Simple Drop guard

Chris: It's basically a Drop with a unit type. Which doesn't seem that useful

Amanieu: Drop guards always carry a value. In most cases you need to wrap the object because you still need to work with the guarded object in the method itself.

Chris: Having a whole new type for this seems overkill.

Amanieu: at most a specific constructor. But even then I don't think this is justified.

The 8472: The proposed with drop is generic anyway so we could always add a specific method for ()

Amanieu: Just close this.

The 8472: Yeah.

Josh: Confirming, we're not rejecting the whole concept of a drop guard, just one that's centered around unit.

Amanieu: yes. The PR has been merged, we already have DropGuard.

Josh: We could consider an additional method on drop guard that doesn't require you to pass unit but it should definitely be the same type.

Amanieu: And even then we're not sure.

(new change proposal) rust.tf/libs628 Implement some arithmetic operations for `std::arch` SIMD types

Amanieu: This is in essence taking __m256i and adding arithmetic operations on it.

The 8472: Don't they have different ??. For the bit ones like or and xor those should be unambiguous.

Josh: I'd agree with that. Having the generic type which is a bag of bits left up to the interpretation seems inappropriate.

Amanieu: The argument is that it's a common extension to the C compiler.

The 8472: do the C compilers have specific support for iax16?

Josh: I don't think so.

Josh: There is one exception that'd be worth entertaining here. I don't tihnk they should have add/subtract/divide. But I'd be open to BitAnd, BitOr, BitXor and Not.

The 8472: I said the same earlier. But even then we sholudn't do the Shift bit operations.

Josh: Agreed.

Amanieu: This isn't an issue on Arm: the arm inttrinsics are fully types. There we could just implement all the operators.

Josh: Sure, but that's not these types, right?

Amanieu: No.

Josh: I'd be open to having these on the specific types on arm because they're sized.

TC: Some of the operations on x86 can also be added.

Josh: That's what The 8472 said earlier.

Amanieu: C has them but I'd still reject them.

TC: To be clear, we're talking about rejecting the arithmetic ones only?

Josh: I'd reject them (the arithmetics, not bitops) on x86

TC: I agree, we shouldn't do the ambiguous ones. But the bitops are good.

Josh: The integer type one says integer vertor type x86 specific and is described as a bag of bits. There's also m128 (4 f32 types) and m128d (2 f64 types) that do have specific interpretations. And those we could consider adding.

The 8472: But then you get float addition, right?

Josh: Yes.

Amanieu: I'd be against adding them in generally.

Josh: I've said you'd be for them in arm.

Amanieu: I've checked the arm spec and tehy're not part of the spec. They're part of the extension. I'd prefer to outright rejecting them even for arm.

Josh: I'm not sure how close portable-simd is here. Just that we shouldn't do them for bags of bits.

TC: If the're unambiguous, what's the argument against this.

The 8472: It's patchwork. For ones we could provied bit operations and not arithmetic, for other types it's the other way around.

Josh: I don't that's a aproblem. They're consistent with them being different types.

The 8472: If you're writing code and you have half of them, you haven't gained that much.

TC: I think you have. This fits my mental model of traits. You implement the traits you can.

Josh: This particular proposal is not saying exclusively the i types. They're sayng the simd core types. They have the specific case covered. We actually just discussed the exact thing we covered and explicitly counted for we shouldn't.

Josh: They're doing exactly what I and The 8472 suggested earlier. Bit operations on things that don't have size and arithmetic operations on things that do have size.

Josh: Based on that I'm inclined to accept the FCP.

TC: +1.

Amanieu: Looking at https://clang.llvm.org/docs/LanguageExtensions.html#vector-operations

Amanieu: All of these are fully-typed vectors unlike the x86 types. It is supprted and the m256i is defined as four f32 vectors.

Josh: Proposal: we should say defer index and index mut. Otherwise we should accept the FCP as proposed.

TC: +1.

Amanieu: This is insta stable. I still don't like this.

Josh: These are immediately really useful.

TC: Even for just xor.

Josh: Can you elaborate on this? You probably have half the intrinsics memorised.

Amanieu: It feels strange we're only providing partial support. I still think portable-simd is the right place for this. If you don't want to memorize all the intrinsics you should just use portable-simd.

TC: I feel there's a the principle at play. You implement the traits you can implement. And here we can do that unambiguously for some of these traits and types. It doesn't force anyone to use these. People can still choose to write out the intrinsics.

The 8472: And I think some people will stick to writing platform specific code. For kernels, video codecs etc.

Josh: To elaborate on that: I think it's reasonable to write x86 or arm-specific code and use intrinsics and ??

Amanieu: I think the common case is you write most of it using portable tyeps and for the platform-specific ones you convert to the those temporarily.

The 8472: In crc32 kernel code, half the lines of code are x86 specific.

Amanieu: But you have to do that there anyway.

The 8472: In that case though it doesn't make much sense for using the portable types anyway.

Amanieu: what about div and rem. We don't have intrinsinsics for those.

The 8472: I think they're meant for floats.

Amanieu: I'm talking for all the types. Div intrinsics only exist for floating point division. And there's no SIMD integer division at all.

The 8472: So we'd only implement it where it exists.

Josh: Right now we'd only providing div on floating point types anyway because the integer ones don't have a size anyway. So we shouldn't be providing the intrinsic there.

The 8472: And we also shouldn't do it for anything that has weird behavior.

Amanieu: Index/IndexMut?

Josh: I already wrote that we were going to postpone those. Why don't we defer Index, defer IndexMut, defer Rem and accept the rest

Amanieu: What else do we have? We have loongarch and wasm with stable simd.

Josh: It's going to requrie platform-specific review so let's request that each arch will have a sperarate RP that will be reviewed by the appropriate expert.

The 8472: What do we do about overflows, negating etc.?

Josh: What do the intrinsics do?

Amanieu: Wrapping.

Josh: Then that's what I'd expect we do here.

Amanieu: Then we'd drop the overflow checks? That's different than what portable-simd does. Portable simd is wrapping.

Josh: Here's the text I'm proposing to post:

We discussed these in today's @rust-lang/libs-api meeting.

We don't want to add the Index/IndexMut operations, based on the discussion in this ACP. And from what we can tell, there isn't a Rem operation available for floating-point SIMD, so let's drop Rem as well.

Other than those, we'd like to accept this ACP. That includes the explicit caveat mentioned in the proposal that the i types on x86 should not provide the arithmetic operations, because those types are a bag of bits that don't specify an integer size.

Please note that each architecture should get a separate PR, so that that PR can be reviewed by an expert for that target.

Josh: I can add a note saying that for any given architecture we should only implement the trait if it has a valid intrinsic we can transtlate it to there.

Amanieu: This seems fine.

(new change proposal) rust.tf/libs627 ACP: `cast_init` method for pointers

Josh: Is this the one specificalyl added at our request because another FCP added this under a confusing naming?

Amanieu: Was that the read_raw_parts?

The 8472: That one we made into a cast array.

Amanieu: This is slice_as_ptr.

The 8472: This one is a constrained cast that allows specific changes so you don't accidentally introduce other type changes. So you can't go from T to U. You stay at T and just change Uninit to Init and vice versa.

Josh: That makes sense.

Amanieu: Should we have cast_uninit as well?

Josh: Going from T to Uninit<T>? Seems reasonable.

Amanieu: Ship it.

The 8472: If something has a const T, then likely something wants to treat it to

Josh: We already allow you change a const *T to mut *T.

The 8472: That was a historical mistake.

TC: I was going to say what The 8472 said. I'm struggling to see what the other one would be useful for.

Amanieu: I'm open to having two separate stabilizations for this. Scott said there's code in the stdlib that would use this.

TC + The 8472: Ah, OK then.

(new change proposal) rust.tf/libs626 `Option::map_iter()` to create an iterator from `Option`

Amanieu: If you have an Option containing an Iterator and you want to get an iterator out of it

Josh: If you have an iterator, give it to me and if it's None, give me a different iterator? Sure, but this name is terrible.

We already have Into<Iterator> for option

Amanieu: flat_iter?

Josh: Looks like Josh Stone (cuviper) already proposed flattened_iter for exactly this reason.

Josh: Objections for using flat_iter or flattened_iter

The 8472: The motivation is that this is not being optimized well. I think we can get most of this by specializing the flatten adapter we already have.

Josh: I don't think it's the only motivation. I don't think the verbosity is okay either.

The 8472: I think you can just call flatten on the iterator.

Josh: yeah you can just call into_iter)().flatten()

TC: I think they're also proposing something more like a flat_map rather than what Josh Stone proposed. That affects the name. Assuming we want the one that takes closure, why don't we just call it flat_map.

Amanieu: There's no mapping happening here.

The 8472: I asked for solution sketch and there's no mapping happening there. Just flatten.

TC: Oh, ok. Would it make sense to take the closure and ??

Amanieu: What are you mapping? The thing in the Option. Just do .map on the Option.

The 8472: Mapping would only make sense if the thing in the option doesn't implement IntoIter and you'd want to do some work to make it iterable. But I don't think anyone is asking for that.

Amanieu: I'm happy just accepting Josh Stone's solution as is.

Josh: Are there objections to Josh Stone's solution?

The 8472: I don't think we strictly need it (we could optimize flatten) but that's not a blocker.

TC: I'm still reading but it seems useful.

Josh: We'll ask for flatten_iter.

TC: Is flat_iter a better name?

Amanieu: Maybe?

TC: It has a nice parity with flat_map.

The 8472: The into method is into_iter so into_flat_iter would work.

TC: +1.

Josh: Commented and marked as accepted.

(new change proposal) rust.tf/libs624 ACP: Proper const `Deref` methods

Josh: It's already available now, being stabilized hopefully in not-too-distant future

Amanieu: Like next six months?

Josh: I hope?

Amanieu: We currently have as_slice and as_mut_slice on Vec. Which is a const version of the Deref. Because the methods are const but Deref isn't.

Josh: This is not asking for Deref but on direct methods.

Amanieu: The're also asking on Deref for CStr

Amanieu: I think that looks reasonable.

Josh: Agreed. And we should also note that when const traits are available, we'll want those too.

The 8472: Isn't the const cstr one problematic because we won't have the length?

Amanieu: Mutating the cstr shouldn't let you change the length of the string. It shouldn't allow you to insert a \0 into the cstr. (checks) there's nothing you can do to the mutable underlying bytes.

The 8472: So why do they want this?

Amanieu: I think cstr is one of the more dangerous bytes.

The 8472: So why are they asking for DerefMut and as_mut

Amanieu: CStr doesn't have anything that gives you a mutable pointer. There's one that gives you an immutable pointer but it has &self so it doesn't have a provenance to let you mutate the bytes.

Amanieu: Since it's controversial, should we exclude cstring?

Josh: Are you also proposing to not add as_mut_c_str?

Amanieu: Yes, because you can't do anything with it.

Josh: I feel at some point we should talk about the proposed change to remove length from cstr or make a thin cstr.

Amanieu: I really want to make it thin so I can make it easier with FFI.

Josh: I want it too, just asking if we want to have a "thin cstr".

(we're tabling this for later)

TC: We do expose into_boxed_c_str. You could then DerefMut that, convert it to a *mut CStr with proper provenance, and mutate through it.

https://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.into_boxed_c_str

TC: That's the same problem (or lack thereof) as in this ACP.

Amanieu: The only mutation you can do to OsStr is make_ascii_{upper/lower}case

Amanieu: I'm happy for OsString and PathBuf. But reject CString because there are no mutable methods. But willing to revisit once there are mutable methods on CStr.

The 8472: Do we guarantee anything about transmute for CStr?

Chris: We can't guarantee anything about CStr if we're planning to change the representation.

The 8472: It doesn't have a guaranteed layout.

Josh: Yes, why don't we defer anything related to CStr and just add all of the other methods.

Amanieu: Agreed.

Chris: Was OsStr okay?

Amanieu: Yes, you can make ascii uppercase/lowercase

Chris: Ok, that's fine

(new change proposal) rust.tf/libs623 Pass file descriptors in std::comand::Command

Josh: Yes, please.

Amanieu: I think we discussed this one already. We said something about this not being the right API.

Josh: But that's not our call. There's a lot of APIs that require a file description.

The 8472: Do they? Because systemd has these listeners, but it also has stuff like the run-dir. Are there other cases that require FDs?

Josh: Yes sometimes you do have a protocol you're trying to follow.

The 8472: Then my original concern stands: you give them a bad option without giving them a good option.

Josh: If someone can make a safe socket, that would be great. But this adds an API that's useful.

TC: Is the argument that you shouldn't be using this because you should use a unix socket?

The 8472: Yes.

TC: What's the argument against this protocol?

The 8472: We went through all the arguments with the JobServer protocol wchich does FD parsing and we got it all wrong. The crate is still subtly broken. There's an open issue that it violates the IO safety. Getting all this to work is very tricky.

Amanieu: I agree but we don't make the protocols.

The 8472: Sure. If you have no choice because some external tool requires you to use it, then that's fair. But if we add this without a safer alternative, people will use it even when they shouldn't it.

Josh: Would you volunteer pursuing that?

The 8472: We've tried this, the RFC got stalled. This is going to be complicated and take a long time.

Josh: I would love to see this as well.

The 8472: But the fd passing is not the only interesting thing. It quickly gets complicated.

Josh: Absolutely. It does.

Josh: But in the meantime.

The 8472: It shouldn't block this ACP but during stabilization that would be my concern.

TC: To double check, what exactly does this do?

Josh: It takes a pair of fds and it passes the file descriptor to the child. If the fd is marked as cloexec it should make it cloexec as well.

TC: What's the exact mechanism for passing the fds to the child?

The 8472: We call fork_exec ??

TC: How does the child know the numbers?

Amanieu: You pass them via CLI arguments, env vars or because you know the protocol.

The 8472: That's where you can get wrong because the file descriptors could get out of sync.

TC: So it's not communicating to the child what the file descriptors are. You still need to pass them to the child somehow. This just takes care of passing the fds at whatever numbers they are. This seems OK then.

Josh: I'd proposa the curent API is wrong. I'd propose "here's a fd number or here's a borrowed fd and ??"

The 8472: Can we have generics with default to 'static? A generic argument with a default value but not for a type but for a lifetime?

Amanieu: Oh, because we need to put the lifetime on the struct.

Josh: only for borrowed fd.

Amanieu: It would be slightly inefficient if you had to dup the fd in Command

Josh: Depends what you'r passing. If you open a pipe and you want to pass one end to the child and you don't intend to keep the end open, I don't think there's inefficiency there.

Chris: What about spawn with fds?

The 8472: If we want to pass something else in the future, this would explode.

Chris: What about spawn_with_options?

The 8472: But Command already carries options.

Josh: Does Command currently do zero allocation? If it does, we could stuff put the thing you're handed into a Box. It doesn't need to be a borrowed object.

Chris: It does a lot of allocation.

The 8472: But then we can just pass an own fd, you don't need a box.

Josh: The concext of inherited file descriptor is not portable.

Chris: We all have an idea of a File.

Josh: There are platforms that don't have file description or handless.

TC: What's it trying to achieve in the sketch? Why do you need raw fd and borrowed fd?

The 8472: ??

TC: So it's for mapping. The RawFd is the target number.

The 8472: I looked at stdio and we have pipes at least. And we have From<File>.

Josh: If you want a generic type, you can accept OwnedFd.

The 8472: The conversion is usually cheap so there's not much benefit.

The 8472: 2 questions: 1. what do we do with the lifetime? 2. Do we want something separate that also works on windows so people can write code for most major platforms?

TC: On the lifetimes question, I think it'd be ok to accept the ACP and then leave someone, as an implementation question, to figure out what's in the realm of possibility.

The 8472: In the handle passing similar on windows?

Chris: We allow a passing a list of handles.

Josh: For BorrowedFd, do we actually need a lifetime in Command? Or can we just say BorrowedFd must live longer than Command? If the method in question takes &mut self. So you could say the BorrowFd you accepted must last longer than Self.

Amanieu: No, because when you call Spawn, it will move the Command. And that will invalidate the lifetime.

Josh: Good point.

The 8472: Spawn takes &mut self.

Josh: We already have this problem. Child STDIN has an implementation anything taht provides AsFd

The 8472: I'm looking at std io and that takes OwnFd and not BorrowedOne

TC: To confirm, this is what Josh you're proposing?:

impl std::os::fd::CommandExt for std::command::Command {
  fn pass_fds<'a, 'b: 'a>(&'a mut self, fds: &'b [(std::os::fd::RawFd, BorrowedFd<'b>)]);
  // Josh:: Actually, I'm proposing:
  fn pass_fd<'a, 'b: 'a>(&'a mut self, fd: std::os::fd::RawFd, file: BorrowedFd<'b>);
  // TC: We could have both, as we do elsewhere.
  // The 8472: E.g. with `args` / `arg`.
}

Amanieu: I think it keeps the mutable borrow of self. Either this doesn't work or it prevents you from ever mutating Command again.

The 8472: You need create a mutable reference first. Assign that to a local, then pass it to OwnFd.

Josh: Right. I just checed and all the impls for std::io explicitly require File or OwnedFd or similar. Except they also do accept child stdout. Roughly speaking we should just accept Into<OwnedFd>

TC: I think that someone should look at the impl approach above and see if that works.

Josh: Yes, someone should look into that.

The 8472: I think the other option is to add a generic type, give it a default and somehow thread a lifetime through that if possible.

Josh: I don't think Defaults don't work the way you want.

Amanieu: This (the code proposal above) doesn't work.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=8ada0f5fb1f9b4bd6412fffca3d47298

Amanieu: It compiles and it shouldn't because I droppeed the file descriptor before

Amanieu: The lifetime on Self is variant but self has no lifetime.

Josh: I think I might see the issue with this. I'm working on it now. I thought at first that Box was the issue. But it doesn't seem so.

TC: It's because of automatic reborrowing. The pass_fd is doing an automatic reborrow here.

Josh: So it's reborrowing to make the borrow of self shorter to make it pass.

Josh: Okay so Into<OwnedFd>?

Josh: If someone wants to have a BorrowedFd, we could have a BorrowedCommand wrapper.

Amanieu: How do people feel about replacing Command in a future edition. Have it lifetime and fix other issues.

Josh: Full support. What are. the other issues with Command?

Amanieu: Can't remember of the top of my head. There was huge thread about whether spawn should consume the command.

Josh: That seems fine.

Josh: I'm fine taking Into<OwnedFd> now and if we fix Command in the future, we could add a lifetime.

Chris: Do we want to creat an issue to track all this?

TC: Does Into<OwnedFd> work in every case here?

Amanieu: It works. You just have to clone it.

The 8472: The alternative is we can accept AsFd and let Command clone it but then the method must return a result because the cloning can fail.

Amanieu: The other lifetime issue was the pre_exec closure.

Josh: Are we accepting the ACP based on OwnedFd. I can write this up.

(new change proposal) rust.tf/libs621 ACP: Add Waker::with_arc_wake

(new change proposal) rust.tf/libs619 slice::get_clamped

(stalled change proposal) rust.tf/libs195 OS-level `thread::Builder` priority and affinity extensions

(stalled change proposal) rust.tf/libs459 ACP: Expose rustc_lexer::unescape Functionality in the proc_macro Crate for Standardized Literal Parsing

(stalled change proposal) rust.tf/libs354 Add titlecase APIs to `char`

(stalled change proposal) rust.tf/libs262 Add infallible variant of RangeFrom::next()

(stalled change proposal) rust.tf/libs347 Context reactor hook

(stalled change proposal) rust.tf/libs348 std::os::unix::env::{argc, argv}

(stalled change proposal) rust.tf/libs344 ACP: Add `std::string::String::replace_and_count` and/or `replace_with`

(stalled change proposal) rust.tf/libs360 make FromResidual #[fundamental]

(stalled change proposal) rust.tf/libs462 impl fmt::Write for BufWriter

(stalled change proposal) rust.tf/libs202 Support for non-blocking and best-effort zero-copy `io::copy`

Generated by fully-automatic-rust-libs-team-triage-meeting-agenda-generator