about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/collections/hash/set.rs449
-rw-r--r--library/std/src/f128.rs98
-rw-r--r--library/std/src/f16.rs97
-rw-r--r--library/std/src/f32.rs84
-rw-r--r--library/std/src/f64.rs84
-rw-r--r--library/std/src/ffi/os_str.rs8
-rw-r--r--library/std/src/ffi/os_str/tests.rs4
-rw-r--r--library/std/src/fs.rs217
-rw-r--r--library/std/src/fs/tests.rs146
-rw-r--r--library/std/src/io/mod.rs45
-rw-r--r--library/std/src/io/tests.rs14
-rw-r--r--library/std/src/os/nuttx/raw.rs2
-rw-r--r--library/std/src/path.rs8
-rw-r--r--library/std/src/path/tests.rs4
-rw-r--r--library/std/src/sync/mpmc/mod.rs2
-rw-r--r--library/std/src/sync/mpsc/mod.rs2
-rw-r--r--library/std/src/sys/os_str/bytes.rs6
-rw-r--r--library/std/src/sys/os_str/wtf8.rs6
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs20
-rw-r--r--library/std/src/sys/pal/hermit/io.rs7
-rw-r--r--library/std/src/sys/pal/solid/fs.rs20
-rw-r--r--library/std/src/sys/pal/solid/io.rs7
-rw-r--r--library/std/src/sys/pal/unix/fs.rs117
-rw-r--r--library/std/src/sys/pal/unix/io.rs7
-rw-r--r--library/std/src/sys/pal/unix/pipe.rs1
-rw-r--r--library/std/src/sys/pal/unsupported/fs.rs20
-rw-r--r--library/std/src/sys/pal/unsupported/io.rs7
-rw-r--r--library/std/src/sys/pal/wasi/fs.rs20
-rw-r--r--library/std/src/sys/pal/wasi/io.rs7
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt4
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs5
-rw-r--r--library/std/src/sys/pal/windows/fs.rs114
-rw-r--r--library/std/src/sys/pal/windows/io.rs7
-rw-r--r--library/std/src/sys_common/wtf8.rs6
34 files changed, 1254 insertions, 391 deletions
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index e1e0eb36d23..f86bcdb4796 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -757,6 +757,47 @@ where
         self.base.get_or_insert_with(value, f)
     }
 
+    /// Gets the given value's corresponding entry in the set for in-place manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry::*;
+    ///
+    /// let mut singles = HashSet::new();
+    /// let mut dupes = HashSet::new();
+    ///
+    /// for ch in "a short treatise on fungi".chars() {
+    ///     if let Vacant(dupe_entry) = dupes.entry(ch) {
+    ///         // We haven't already seen a duplicate, so
+    ///         // check if we've at least seen it once.
+    ///         match singles.entry(ch) {
+    ///             Vacant(single_entry) => {
+    ///                 // We found a new character for the first time.
+    ///                 single_entry.insert()
+    ///             }
+    ///             Occupied(single_entry) => {
+    ///                 // We've already seen this once, "move" it to dupes.
+    ///                 single_entry.remove();
+    ///                 dupe_entry.insert();
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert!(!singles.contains(&'t') && dupes.contains(&'t'));
+    /// assert!(singles.contains(&'u') && !dupes.contains(&'u'));
+    /// assert!(!singles.contains(&'v') && !dupes.contains(&'v'));
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn entry(&mut self, value: T) -> Entry<'_, T, S> {
+        map_entry(self.base.entry(value))
+    }
+
     /// Returns `true` if `self` has no elements in common with `other`.
     /// This is equivalent to checking for an empty intersection.
     ///
@@ -935,6 +976,14 @@ where
     }
 }
 
+#[inline]
+fn map_entry<'a, K: 'a, V: 'a>(raw: base::Entry<'a, K, V>) -> Entry<'a, K, V> {
+    match raw {
+        base::Entry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }),
+        base::Entry::Vacant(base) => Entry::Vacant(VacantEntry { base }),
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, S> Clone for HashSet<T, S>
 where
@@ -1865,6 +1914,406 @@ where
     }
 }
 
+/// A view into a single entry in a set, which may either be vacant or occupied.
+///
+/// This `enum` is constructed from the [`entry`] method on [`HashSet`].
+///
+/// [`HashSet`]: struct.HashSet.html
+/// [`entry`]: struct.HashSet.html#method.entry
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::HashSet;
+///
+/// let mut set = HashSet::new();
+/// set.extend(["a", "b", "c"]);
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing value (insert)
+/// let entry = set.entry("a");
+/// let _raw_o = entry.insert();
+/// assert_eq!(set.len(), 3);
+/// // Nonexistent value (insert)
+/// set.entry("d").insert();
+///
+/// // Existing value (or_insert)
+/// set.entry("b").or_insert();
+/// // Nonexistent value (or_insert)
+/// set.entry("e").or_insert();
+///
+/// println!("Our HashSet: {:?}", set);
+///
+/// let mut vec: Vec<_> = set.iter().copied().collect();
+/// // The `Iter` iterator produces items in arbitrary order, so the
+/// // items must be sorted to test them against a sorted array.
+/// vec.sort_unstable();
+/// assert_eq!(vec, ["a", "b", "c", "d", "e"]);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub enum Entry<'a, T, S> {
+    /// An occupied entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::from(["a", "b"]);
+    ///
+    /// match set.entry("a") {
+    ///     Entry::Vacant(_) => unreachable!(),
+    ///     Entry::Occupied(_) => { }
+    /// }
+    /// ```
+    Occupied(OccupiedEntry<'a, T, S>),
+
+    /// A vacant entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// match set.entry("a") {
+    ///     Entry::Occupied(_) => unreachable!(),
+    ///     Entry::Vacant(_) => { }
+    /// }
+    /// ```
+    Vacant(VacantEntry<'a, T, S>),
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for Entry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
+            Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
+        }
+    }
+}
+
+/// A view into an occupied entry in a `HashSet`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::{Entry, HashSet};
+///
+/// let mut set = HashSet::new();
+/// set.extend(["a", "b", "c"]);
+///
+/// let _entry_o = set.entry("a").insert();
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing key
+/// match set.entry("a") {
+///     Entry::Vacant(_) => unreachable!(),
+///     Entry::Occupied(view) => {
+///         assert_eq!(view.get(), &"a");
+///     }
+/// }
+///
+/// assert_eq!(set.len(), 3);
+///
+/// // Existing key (take)
+/// match set.entry("c") {
+///     Entry::Vacant(_) => unreachable!(),
+///     Entry::Occupied(view) => {
+///         assert_eq!(view.remove(), "c");
+///     }
+/// }
+/// assert_eq!(set.get(&"c"), None);
+/// assert_eq!(set.len(), 2);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub struct OccupiedEntry<'a, T, S> {
+    base: base::OccupiedEntry<'a, T, S>,
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for OccupiedEntry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OccupiedEntry").field("value", self.get()).finish()
+    }
+}
+
+/// A view into a vacant entry in a `HashSet`.
+/// It is part of the [`Entry`] enum.
+///
+/// [`Entry`]: enum.Entry.html
+///
+/// # Examples
+///
+/// ```
+/// #![feature(hash_set_entry)]
+///
+/// use std::collections::hash_set::{Entry, HashSet};
+///
+/// let mut set = HashSet::<&str>::new();
+///
+/// let entry_v = match set.entry("a") {
+///     Entry::Vacant(view) => view,
+///     Entry::Occupied(_) => unreachable!(),
+/// };
+/// entry_v.insert();
+/// assert!(set.contains("a") && set.len() == 1);
+///
+/// // Nonexistent key (insert)
+/// match set.entry("b") {
+///     Entry::Vacant(view) => view.insert(),
+///     Entry::Occupied(_) => unreachable!(),
+/// }
+/// assert!(set.contains("b") && set.len() == 2);
+/// ```
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+pub struct VacantEntry<'a, T, S> {
+    base: base::VacantEntry<'a, T, S>,
+}
+
+#[unstable(feature = "hash_set_entry", issue = "60896")]
+impl<T: fmt::Debug, S> fmt::Debug for VacantEntry<'_, T, S> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_tuple("VacantEntry").field(self.get()).finish()
+    }
+}
+
+impl<'a, T, S> Entry<'a, T, S> {
+    /// Sets the value of the entry, and returns an OccupiedEntry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// let entry = set.entry("horseyland").insert();
+    ///
+    /// assert_eq!(entry.get(), &"horseyland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn insert(self) -> OccupiedEntry<'a, T, S>
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        match self {
+            Entry::Occupied(entry) => entry,
+            Entry::Vacant(entry) => entry.insert_entry(),
+        }
+    }
+
+    /// Ensures a value is in the entry by inserting if it was vacant.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// // nonexistent key
+    /// set.entry("poneyland").or_insert();
+    /// assert!(set.contains("poneyland"));
+    ///
+    /// // existing key
+    /// set.entry("poneyland").or_insert();
+    /// assert!(set.contains("poneyland"));
+    /// assert_eq!(set.len(), 1);
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn or_insert(self)
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        if let Entry::Vacant(entry) = self {
+            entry.insert();
+        }
+    }
+
+    /// Returns a reference to this entry's value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// set.entry("poneyland").or_insert();
+    ///
+    /// // existing key
+    /// assert_eq!(set.entry("poneyland").get(), &"poneyland");
+    /// // nonexistent key
+    /// assert_eq!(set.entry("horseland").get(), &"horseland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        match *self {
+            Entry::Occupied(ref entry) => entry.get(),
+            Entry::Vacant(ref entry) => entry.get(),
+        }
+    }
+}
+
+impl<T, S> OccupiedEntry<'_, T, S> {
+    /// Gets a reference to the value in the entry.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    /// set.entry("poneyland").or_insert();
+    ///
+    /// match set.entry("poneyland") {
+    ///     Entry::Vacant(_) => panic!(),
+    ///     Entry::Occupied(entry) => assert_eq!(entry.get(), &"poneyland"),
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        self.base.get()
+    }
+
+    /// Takes the value out of the entry, and returns it.
+    /// Keeps the allocated memory for reuse.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry;
+    ///
+    /// let mut set = HashSet::new();
+    /// // The set is empty
+    /// assert!(set.is_empty() && set.capacity() == 0);
+    ///
+    /// set.entry("poneyland").or_insert();
+    /// let capacity_before_remove = set.capacity();
+    ///
+    /// if let Entry::Occupied(o) = set.entry("poneyland") {
+    ///     assert_eq!(o.remove(), "poneyland");
+    /// }
+    ///
+    /// assert_eq!(set.contains("poneyland"), false);
+    /// // Now set hold none elements but capacity is equal to the old one
+    /// assert!(set.len() == 0 && set.capacity() == capacity_before_remove);
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn remove(self) -> T {
+        self.base.remove()
+    }
+}
+
+impl<'a, T, S> VacantEntry<'a, T, S> {
+    /// Gets a reference to the value that would be used when inserting
+    /// through the `VacantEntry`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::new();
+    /// assert_eq!(set.entry("poneyland").get(), &"poneyland");
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn get(&self) -> &T {
+        self.base.get()
+    }
+
+    /// Take ownership of the value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::hash_set::{Entry, HashSet};
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// match set.entry("poneyland") {
+    ///     Entry::Occupied(_) => panic!(),
+    ///     Entry::Vacant(v) => assert_eq!(v.into_value(), "poneyland"),
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn into_value(self) -> T {
+        self.base.into_value()
+    }
+
+    /// Sets the value of the entry with the VacantEntry's value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(hash_set_entry)]
+    ///
+    /// use std::collections::HashSet;
+    /// use std::collections::hash_set::Entry;
+    ///
+    /// let mut set = HashSet::new();
+    ///
+    /// if let Entry::Vacant(o) = set.entry("poneyland") {
+    ///     o.insert();
+    /// }
+    /// assert!(set.contains("poneyland"));
+    /// ```
+    #[inline]
+    #[unstable(feature = "hash_set_entry", issue = "60896")]
+    pub fn insert(self)
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        self.base.insert();
+    }
+
+    #[inline]
+    fn insert_entry(self) -> OccupiedEntry<'a, T, S>
+    where
+        T: Hash,
+        S: BuildHasher,
+    {
+        OccupiedEntry { base: self.base.insert() }
+    }
+}
+
 #[allow(dead_code)]
 fn assert_covariance() {
     fn set<'new>(v: HashSet<&'static str>) -> HashSet<&'new str> {
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index 229f979b5b1..e93e915159e 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -188,104 +188,6 @@ impl f128 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`.
-    ///
-    /// This function always returns the precise result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f128)]
-    /// # #[cfg(reliable_f128)] {
-    ///
-    /// let x = 3.5_f128;
-    /// let y = -3.5_f128;
-    ///
-    /// assert_eq!(x.abs(), x);
-    /// assert_eq!(y.abs(), -y);
-    ///
-    /// assert!(f128::NAN.abs().is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn abs(self) -> Self {
-        // FIXME(f16_f128): replace with `intrinsics::fabsf128` when available
-        // We don't do this now because LLVM has lowering bugs for f128 math.
-        Self::from_bits(self.to_bits() & !(1 << 127))
-    }
-
-    /// Returns a number that represents the sign of `self`.
-    ///
-    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
-    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - NaN if the number is NaN
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f128)]
-    /// # #[cfg(reliable_f128_math)] {
-    ///
-    /// let f = 3.5_f128;
-    ///
-    /// assert_eq!(f.signum(), 1.0);
-    /// assert_eq!(f128::NEG_INFINITY.signum(), -1.0);
-    ///
-    /// assert!(f128::NAN.signum().is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn signum(self) -> f128 {
-        if self.is_nan() { Self::NAN } else { 1.0_f128.copysign(self) }
-    }
-
-    /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `sign`.
-    ///
-    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
-    /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
-    /// returned.
-    ///
-    /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
-    /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
-    /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
-    /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
-    /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
-    /// info.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f128)]
-    /// # #[cfg(reliable_f128_math)] {
-    ///
-    /// let f = 3.5_f128;
-    ///
-    /// assert_eq!(f.copysign(0.42), 3.5_f128);
-    /// assert_eq!(f.copysign(-0.42), -3.5_f128);
-    /// assert_eq!((-f).copysign(0.42), 3.5_f128);
-    /// assert_eq!((-f).copysign(-0.42), -3.5_f128);
-    ///
-    /// assert!(f128::NAN.copysign(1.0).is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f128", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn copysign(self, sign: f128) -> f128 {
-        unsafe { intrinsics::copysignf128(self, sign) }
-    }
-
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
     /// error, yielding a more accurate result than an unfused multiply-add.
     ///
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index bed21cda1cd..5b7fcaa28e0 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -188,103 +188,6 @@ impl f16 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`.
-    ///
-    /// This function always returns the precise result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f16)]
-    /// # #[cfg(reliable_f16)] {
-    ///
-    /// let x = 3.5_f16;
-    /// let y = -3.5_f16;
-    ///
-    /// assert_eq!(x.abs(), x);
-    /// assert_eq!(y.abs(), -y);
-    ///
-    /// assert!(f16::NAN.abs().is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn abs(self) -> Self {
-        // FIXME(f16_f128): replace with `intrinsics::fabsf16` when available
-        Self::from_bits(self.to_bits() & !(1 << 15))
-    }
-
-    /// Returns a number that represents the sign of `self`.
-    ///
-    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
-    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - NaN if the number is NaN
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f16)]
-    /// # #[cfg(reliable_f16_math)] {
-    ///
-    /// let f = 3.5_f16;
-    ///
-    /// assert_eq!(f.signum(), 1.0);
-    /// assert_eq!(f16::NEG_INFINITY.signum(), -1.0);
-    ///
-    /// assert!(f16::NAN.signum().is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn signum(self) -> f16 {
-        if self.is_nan() { Self::NAN } else { 1.0_f16.copysign(self) }
-    }
-
-    /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `sign`.
-    ///
-    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
-    /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
-    /// returned.
-    ///
-    /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
-    /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
-    /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
-    /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
-    /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
-    /// info.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(f16)]
-    /// # #[cfg(reliable_f16_math)] {
-    ///
-    /// let f = 3.5_f16;
-    ///
-    /// assert_eq!(f.copysign(0.42), 3.5_f16);
-    /// assert_eq!(f.copysign(-0.42), -3.5_f16);
-    /// assert_eq!((-f).copysign(0.42), 3.5_f16);
-    /// assert_eq!((-f).copysign(-0.42), -3.5_f16);
-    ///
-    /// assert!(f16::NAN.copysign(1.0).is_nan());
-    /// # }
-    /// ```
-    #[inline]
-    #[rustc_allow_incoherent_impl]
-    #[unstable(feature = "f16", issue = "116909")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    pub const fn copysign(self, sign: f16) -> f16 {
-        unsafe { intrinsics::copysignf16(self, sign) }
-    }
-
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
     /// error, yielding a more accurate result than an unfused multiply-add.
     ///
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 30cf4e1f756..7cb285bbff5 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -176,90 +176,6 @@ impl f32 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`.
-    ///
-    /// This function always returns the precise result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let x = 3.5_f32;
-    /// let y = -3.5_f32;
-    ///
-    /// assert_eq!(x.abs(), x);
-    /// assert_eq!(y.abs(), -y);
-    ///
-    /// assert!(f32::NAN.abs().is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[inline]
-    pub const fn abs(self) -> f32 {
-        unsafe { intrinsics::fabsf32(self) }
-    }
-
-    /// Returns a number that represents the sign of `self`.
-    ///
-    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
-    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - NaN if the number is NaN
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let f = 3.5_f32;
-    ///
-    /// assert_eq!(f.signum(), 1.0);
-    /// assert_eq!(f32::NEG_INFINITY.signum(), -1.0);
-    ///
-    /// assert!(f32::NAN.signum().is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[inline]
-    pub const fn signum(self) -> f32 {
-        if self.is_nan() { Self::NAN } else { 1.0_f32.copysign(self) }
-    }
-
-    /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `sign`.
-    ///
-    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
-    /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
-    /// returned.
-    ///
-    /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
-    /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
-    /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
-    /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
-    /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
-    /// info.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let f = 3.5_f32;
-    ///
-    /// assert_eq!(f.copysign(0.42), 3.5_f32);
-    /// assert_eq!(f.copysign(-0.42), -3.5_f32);
-    /// assert_eq!((-f).copysign(0.42), 3.5_f32);
-    /// assert_eq!((-f).copysign(-0.42), -3.5_f32);
-    ///
-    /// assert!(f32::NAN.copysign(1.0).is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[inline]
-    #[stable(feature = "copysign", since = "1.35.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    pub const fn copysign(self, sign: f32) -> f32 {
-        unsafe { intrinsics::copysignf32(self, sign) }
-    }
-
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
     /// error, yielding a more accurate result than an unfused multiply-add.
     ///
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 51d5476b372..47163c272de 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -176,90 +176,6 @@ impl f64 {
         self - self.trunc()
     }
 
-    /// Computes the absolute value of `self`.
-    ///
-    /// This function always returns the precise result.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let x = 3.5_f64;
-    /// let y = -3.5_f64;
-    ///
-    /// assert_eq!(x.abs(), x);
-    /// assert_eq!(y.abs(), -y);
-    ///
-    /// assert!(f64::NAN.abs().is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[inline]
-    pub const fn abs(self) -> f64 {
-        unsafe { intrinsics::fabsf64(self) }
-    }
-
-    /// Returns a number that represents the sign of `self`.
-    ///
-    /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
-    /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
-    /// - NaN if the number is NaN
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let f = 3.5_f64;
-    ///
-    /// assert_eq!(f.signum(), 1.0);
-    /// assert_eq!(f64::NEG_INFINITY.signum(), -1.0);
-    ///
-    /// assert!(f64::NAN.signum().is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[inline]
-    pub const fn signum(self) -> f64 {
-        if self.is_nan() { Self::NAN } else { 1.0_f64.copysign(self) }
-    }
-
-    /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `sign`.
-    ///
-    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise equal to `-self`.
-    /// If `self` is a NaN, then a NaN with the same payload as `self` and the sign bit of `sign` is
-    /// returned.
-    ///
-    /// If `sign` is a NaN, then this operation will still carry over its sign into the result. Note
-    /// that IEEE 754 doesn't assign any meaning to the sign bit in case of a NaN, and as Rust
-    /// doesn't guarantee that the bit pattern of NaNs are conserved over arithmetic operations, the
-    /// result of `copysign` with `sign` being a NaN might produce an unexpected or non-portable
-    /// result. See the [specification of NaN bit patterns](primitive@f32#nan-bit-patterns) for more
-    /// info.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let f = 3.5_f64;
-    ///
-    /// assert_eq!(f.copysign(0.42), 3.5_f64);
-    /// assert_eq!(f.copysign(-0.42), -3.5_f64);
-    /// assert_eq!((-f).copysign(0.42), 3.5_f64);
-    /// assert_eq!((-f).copysign(-0.42), -3.5_f64);
-    ///
-    /// assert!(f64::NAN.copysign(1.0).is_nan());
-    /// ```
-    #[rustc_allow_incoherent_impl]
-    #[must_use = "method returns a new number and does not mutate the original value"]
-    #[stable(feature = "copysign", since = "1.35.0")]
-    #[rustc_const_unstable(feature = "const_float_methods", issue = "130843")]
-    #[inline]
-    pub const fn copysign(self, sign: f64) -> f64 {
-        unsafe { intrinsics::copysignf64(self, sign) }
-    }
-
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
     /// error, yielding a more accurate result than an unfused multiply-add.
     ///
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index b19d482feaa..79dfb47d0c4 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -112,7 +112,7 @@ impl crate::sealed::Sealed for OsString {}
 /// [conversions]: super#conversions
 #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
 #[stable(feature = "rust1", since = "1.0.0")]
-// `OsStr::from_inner` current implementation relies
+// `OsStr::from_inner` and `impl CloneToUninit for OsStr` current implementation relies
 // on `OsStr` being layout-compatible with `Slice`.
 // However, `OsStr` layout is considered an implementation detail and must not be relied upon.
 #[repr(transparent)]
@@ -1278,9 +1278,9 @@ impl Clone for Box<OsStr> {
 unsafe impl CloneToUninit for OsStr {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
-    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: we're just a wrapper around a platform-specific Slice
-        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: we're just a transparent wrapper around a platform-specific Slice
+        unsafe { self.inner.clone_to_uninit(dst) }
     }
 }
 
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
index 67147934b4d..cbec44c8626 100644
--- a/library/std/src/ffi/os_str/tests.rs
+++ b/library/std/src/ffi/os_str/tests.rs
@@ -294,12 +294,12 @@ fn clone_to_uninit() {
     let a = OsStr::new("hello.txt");
 
     let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<OsStr>(a)];
-    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut OsStr) };
+    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) };
     assert_eq!(a.as_encoded_bytes(), unsafe { MaybeUninit::slice_assume_init_ref(&storage) });
 
     let mut b: Box<OsStr> = OsStr::new("world.exe").into();
     assert_eq!(size_of_val::<OsStr>(a), size_of_val::<OsStr>(&b));
     assert_ne!(a, &*b);
-    unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b)) };
+    unsafe { a.clone_to_uninit(ptr::from_mut::<OsStr>(&mut b).cast()) };
     assert_eq!(a, &*b);
 }
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 3079c8b1d90..76fdb1a4ffd 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -624,6 +624,223 @@ impl File {
         self.inner.datasync()
     }
 
+    /// Acquire an exclusive advisory lock on the file. Blocks until the lock can be acquired.
+    ///
+    /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
+    /// another lock.
+    ///
+    /// If this file handle, or a clone of it, already holds an advisory lock the exact behavior is
+    /// unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then an exclusive lock is held.
+    ///
+    /// If the file not open for writing, it is unspecified whether this function returns an error.
+    ///
+    /// Note, this is an advisory lock meant to interact with [`lock_shared`], [`try_lock`],
+    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
+    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` flag,
+    /// and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK` flag. Note that,
+    /// this [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// [`lock_shared`]: File::lock_shared
+    /// [`try_lock`]: File::try_lock
+    /// [`try_lock_shared`]: File::try_lock_shared
+    /// [`unlock`]: File::unlock
+    /// [`read`]: Read::read
+    /// [`write`]: Write::write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_lock)]
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///     f.lock()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_lock", issue = "130994")]
+    pub fn lock(&self) -> io::Result<()> {
+        self.inner.lock()
+    }
+
+    /// Acquire a shared advisory lock on the file. Blocks until the lock can be acquired.
+    ///
+    /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
+    /// none may hold an exclusive lock.
+    ///
+    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
+    /// unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then a shared lock is held.
+    ///
+    /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
+    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
+    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` flag,
+    /// and the `LockFileEx` function on Windows. Note that, this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// [`lock`]: File::lock
+    /// [`try_lock`]: File::try_lock
+    /// [`try_lock_shared`]: File::try_lock_shared
+    /// [`unlock`]: File::unlock
+    /// [`read`]: Read::read
+    /// [`write`]: Write::write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_lock)]
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///     f.lock_shared()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_lock", issue = "130994")]
+    pub fn lock_shared(&self) -> io::Result<()> {
+        self.inner.lock_shared()
+    }
+
+    /// Acquire an exclusive advisory lock on the file. Returns `Ok(false)` if the file is locked.
+    ///
+    /// This acquires an exclusive advisory lock; no other file handle to this file may acquire
+    /// another lock.
+    ///
+    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
+    /// unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then an exclusive lock is held.
+    ///
+    /// If the file not open for writing, it is unspecified whether this function returns an error.
+    ///
+    /// Note, this is an advisory lock meant to interact with [`lock`], [`lock_shared`],
+    /// [`try_lock_shared`], and [`unlock`]. Its interactions with other methods, such as [`read`]
+    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `flock` function on Unix with the `LOCK_EX` and
+    /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the `LOCKFILE_EXCLUSIVE_LOCK`
+    /// and `LOCKFILE_FAIL_IMMEDIATELY` flags. Note that, this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// [`lock`]: File::lock
+    /// [`lock_shared`]: File::lock_shared
+    /// [`try_lock_shared`]: File::try_lock_shared
+    /// [`unlock`]: File::unlock
+    /// [`read`]: Read::read
+    /// [`write`]: Write::write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_lock)]
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///     f.try_lock()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_lock", issue = "130994")]
+    pub fn try_lock(&self) -> io::Result<bool> {
+        self.inner.try_lock()
+    }
+
+    /// Acquire a shared advisory lock on the file.
+    /// Returns `Ok(false)` if the file is exclusively locked.
+    ///
+    /// This acquires a shared advisory lock; more than one file handle may hold a shared lock, but
+    /// none may hold an exclusive lock.
+    ///
+    /// If this file handle, or a clone of it, already holds an advisory lock, the exact behavior is
+    /// unspecified and platform dependent, including the possibility that it will deadlock.
+    /// However, if this method returns, then a shared lock is held.
+    ///
+    /// Note, this is an advisory lock meant to interact with [`lock`], [`try_lock`],
+    /// [`try_lock`], and [`unlock`]. Its interactions with other methods, such as [`read`]
+    /// and [`write`] are platform specific, and it may or may not cause non-lockholders to block.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `flock` function on Unix with the `LOCK_SH` and
+    /// `LOCK_NB` flags, and the `LockFileEx` function on Windows with the
+    /// `LOCKFILE_FAIL_IMMEDIATELY` flag. Note that, this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// [`lock`]: File::lock
+    /// [`lock_shared`]: File::lock_shared
+    /// [`try_lock`]: File::try_lock
+    /// [`unlock`]: File::unlock
+    /// [`read`]: Read::read
+    /// [`write`]: Write::write
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_lock)]
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///     f.try_lock_shared()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_lock", issue = "130994")]
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        self.inner.try_lock_shared()
+    }
+
+    /// Release all locks on the file.
+    ///
+    /// All remaining locks are released when the file handle, and all clones of it, are dropped.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `flock` function on Unix with the `LOCK_UN` flag,
+    /// and the `UnlockFile` function on Windows. Note that, this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: io#platform-specific-behavior
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(file_lock)]
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("foo.txt")?;
+    ///     f.lock()?;
+    ///     f.unlock()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[unstable(feature = "file_lock", issue = "130994")]
+    pub fn unlock(&self) -> io::Result<()> {
+        self.inner.unlock()
+    }
+
     /// Truncates or extends the underlying file, updating the size of
     /// this file to become `size`.
     ///
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 0672fe6f771..018e1958641 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -204,6 +204,152 @@ fn file_test_io_seek_and_write() {
 }
 
 #[test]
+#[cfg(any(
+    windows,
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_vendor = "apple",
+))]
+fn file_lock_multiple_shared() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_multiple_shared_test.txt");
+    let f1 = check!(File::create(filename));
+    let f2 = check!(OpenOptions::new().write(true).open(filename));
+
+    // Check that we can acquire concurrent shared locks
+    check!(f1.lock_shared());
+    check!(f2.lock_shared());
+    check!(f1.unlock());
+    check!(f2.unlock());
+    assert!(check!(f1.try_lock_shared()));
+    assert!(check!(f2.try_lock_shared()));
+}
+
+#[test]
+#[cfg(any(
+    windows,
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_vendor = "apple",
+))]
+fn file_lock_blocking() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_blocking_test.txt");
+    let f1 = check!(File::create(filename));
+    let f2 = check!(OpenOptions::new().write(true).open(filename));
+
+    // Check that shared locks block exclusive locks
+    check!(f1.lock_shared());
+    assert!(!check!(f2.try_lock()));
+    check!(f1.unlock());
+
+    // Check that exclusive locks block shared locks
+    check!(f1.lock());
+    assert!(!check!(f2.try_lock_shared()));
+}
+
+#[test]
+#[cfg(any(
+    windows,
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_vendor = "apple",
+))]
+fn file_lock_drop() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_dup_test.txt");
+    let f1 = check!(File::create(filename));
+    let f2 = check!(OpenOptions::new().write(true).open(filename));
+
+    // Check that locks are released when the File is dropped
+    check!(f1.lock_shared());
+    assert!(!check!(f2.try_lock()));
+    drop(f1);
+    assert!(check!(f2.try_lock()));
+}
+
+#[test]
+#[cfg(any(
+    windows,
+    target_os = "freebsd",
+    target_os = "linux",
+    target_os = "netbsd",
+    target_vendor = "apple",
+))]
+fn file_lock_dup() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_dup_test.txt");
+    let f1 = check!(File::create(filename));
+    let f2 = check!(OpenOptions::new().write(true).open(filename));
+
+    // Check that locks are not dropped if the File has been cloned
+    check!(f1.lock_shared());
+    assert!(!check!(f2.try_lock()));
+    let cloned = check!(f1.try_clone());
+    drop(f1);
+    assert!(!check!(f2.try_lock()));
+    drop(cloned)
+}
+
+#[test]
+#[cfg(windows)]
+fn file_lock_double_unlock() {
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_double_unlock_test.txt");
+    let f1 = check!(File::create(filename));
+    let f2 = check!(OpenOptions::new().write(true).open(filename));
+
+    // On Windows a file handle may acquire both a shared and exclusive lock.
+    // Check that both are released by unlock()
+    check!(f1.lock());
+    check!(f1.lock_shared());
+    assert!(!check!(f2.try_lock()));
+    check!(f1.unlock());
+    assert!(check!(f2.try_lock()));
+}
+
+#[test]
+#[cfg(windows)]
+fn file_lock_blocking_async() {
+    use crate::thread::{sleep, spawn};
+    const FILE_FLAG_OVERLAPPED: u32 = 0x40000000;
+
+    let tmpdir = tmpdir();
+    let filename = &tmpdir.join("file_lock_blocking_async.txt");
+    let f1 = check!(File::create(filename));
+    let f2 =
+        check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename));
+
+    check!(f1.lock());
+
+    // Ensure that lock() is synchronous when the file is opened for asynchronous IO
+    let t = spawn(move || {
+        check!(f2.lock());
+    });
+    sleep(Duration::from_secs(1));
+    assert!(!t.is_finished());
+    check!(f1.unlock());
+    t.join().unwrap();
+
+    // Ensure that lock_shared() is synchronous when the file is opened for asynchronous IO
+    let f2 =
+        check!(OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).write(true).open(filename));
+    check!(f1.lock());
+
+    // Ensure that lock() is synchronous when the file is opened for asynchronous IO
+    let t = spawn(move || {
+        check!(f2.lock_shared());
+    });
+    sleep(Duration::from_secs(1));
+    assert!(!t.is_finished());
+    check!(f1.unlock());
+    t.join().unwrap();
+}
+
+#[test]
 fn file_test_io_seek_shakedown() {
     //                   01234567890123
     let initial_msg = "qwer-asdf-zxcv";
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 71dfd0676c9..21e70774954 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1340,6 +1340,25 @@ impl<'a> IoSliceMut<'a> {
             bufs[0].advance(left);
         }
     }
+
+    /// Get the underlying bytes as a mutable slice with the original lifetime.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(io_slice_as_bytes)]
+    /// use std::io::IoSliceMut;
+    ///
+    /// let mut data = *b"abcdef";
+    /// let io_slice = IoSliceMut::new(&mut data);
+    /// io_slice.into_slice()[0] = b'A';
+    ///
+    /// assert_eq!(&data, b"Abcdef");
+    /// ```
+    #[unstable(feature = "io_slice_as_bytes", issue = "132818")]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        self.0.into_slice()
+    }
 }
 
 #[stable(feature = "iovec", since = "1.36.0")]
@@ -1482,6 +1501,32 @@ impl<'a> IoSlice<'a> {
             bufs[0].advance(left);
         }
     }
+
+    /// Get the underlying bytes as a slice with the original lifetime.
+    ///
+    /// This doesn't borrow from `self`, so is less restrictive than calling
+    /// `.deref()`, which does.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(io_slice_as_bytes)]
+    /// use std::io::IoSlice;
+    ///
+    /// let data = b"abcdef";
+    ///
+    /// let mut io_slice = IoSlice::new(data);
+    /// let tail = &io_slice.as_slice()[3..];
+    ///
+    /// // This works because `tail` doesn't borrow `io_slice`
+    /// io_slice = IoSlice::new(tail);
+    ///
+    /// assert_eq!(io_slice.as_slice(), b"def");
+    /// ```
+    #[unstable(feature = "io_slice_as_bytes", issue = "132818")]
+    pub const fn as_slice(self) -> &'a [u8] {
+        self.0.as_slice()
+    }
 }
 
 #[stable(feature = "iovec", since = "1.36.0")]
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 56b71c47dc7..89e806c0891 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -531,6 +531,20 @@ fn io_slice_advance_slices_beyond_total_length() {
     assert!(bufs.is_empty());
 }
 
+#[test]
+fn io_slice_as_slice() {
+    let buf = [1; 8];
+    let slice = IoSlice::new(&buf).as_slice();
+    assert_eq!(slice, buf);
+}
+
+#[test]
+fn io_slice_into_slice() {
+    let mut buf = [1; 8];
+    let slice = IoSliceMut::new(&mut buf).into_slice();
+    assert_eq!(slice, [1; 8]);
+}
+
 /// Creates a new writer that reads from at most `n_bufs` and reads
 /// `per_call` bytes (in total) per call to write.
 fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter {
diff --git a/library/std/src/os/nuttx/raw.rs b/library/std/src/os/nuttx/raw.rs
index 113079cf4ab..431e66d69a3 100644
--- a/library/std/src/os/nuttx/raw.rs
+++ b/library/std/src/os/nuttx/raw.rs
@@ -1,4 +1,4 @@
-//! rtems raw type definitions
+//! NuttX raw type definitions
 
 #![stable(feature = "raw_ext", since = "1.1.0")]
 #![deprecated(
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 5662a44d832..b0291e3aa19 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2128,7 +2128,7 @@ impl AsRef<OsStr> for PathBuf {
 /// ```
 #[cfg_attr(not(test), rustc_diagnostic_item = "Path")]
 #[stable(feature = "rust1", since = "1.0.0")]
-// `Path::new` current implementation relies
+// `Path::new` and `impl CloneToUninit for Path` current implementation relies
 // on `Path` being layout-compatible with `OsStr`.
 // However, `Path` layout is considered an implementation detail and must not be relied upon.
 #[repr(transparent)]
@@ -3170,9 +3170,9 @@ impl Path {
 unsafe impl CloneToUninit for Path {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
-    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: Path is just a wrapper around OsStr
-        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: Path is just a transparent wrapper around OsStr
+        unsafe { self.inner.clone_to_uninit(dst) }
     }
 }
 
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index b75793d2bc9..ff3f7151bb8 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -2068,7 +2068,7 @@ fn clone_to_uninit() {
     let a = Path::new("hello.txt");
 
     let mut storage = vec![MaybeUninit::<u8>::uninit(); size_of_val::<Path>(a)];
-    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()) as *mut Path) };
+    unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) };
     assert_eq!(a.as_os_str().as_encoded_bytes(), unsafe {
         MaybeUninit::slice_assume_init_ref(&storage)
     });
@@ -2076,6 +2076,6 @@ fn clone_to_uninit() {
     let mut b: Box<Path> = Path::new("world.exe").into();
     assert_eq!(size_of_val::<Path>(a), size_of_val::<Path>(&b));
     assert_ne!(a, &*b);
-    unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b)) };
+    unsafe { a.clone_to_uninit(ptr::from_mut::<Path>(&mut b).cast()) };
     assert_eq!(a, &*b);
 }
diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs
index 44e146a89ba..0cf4902d6d5 100644
--- a/library/std/src/sync/mpmc/mod.rs
+++ b/library/std/src/sync/mpmc/mod.rs
@@ -153,6 +153,7 @@ use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::time::{Duration, Instant};
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`] in
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
@@ -201,6 +202,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 }
 
 /// Creates a new synchronous, bounded channel.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`]
 /// in the same order as it was sent. Like asynchronous [`channel`]s, the
 /// [`Receiver`] will block until a message becomes available. `sync_channel`
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index 83a93a06369..c86b546e011 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -483,6 +483,7 @@ pub enum TrySendError<T> {
 }
 
 /// Creates a new asynchronous channel, returning the sender/receiver halves.
+///
 /// All data sent on the [`Sender`] will become available on the [`Receiver`] in
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
@@ -527,6 +528,7 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 }
 
 /// Creates a new synchronous, bounded channel.
+///
 /// All data sent on the [`SyncSender`] will become available on the [`Receiver`]
 /// in the same order as it was sent. Like asynchronous [`channel`]s, the
 /// [`Receiver`] will block until a message becomes available. `sync_channel`
diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs
index 8e0609fe48c..5b65d862be1 100644
--- a/library/std/src/sys/os_str/bytes.rs
+++ b/library/std/src/sys/os_str/bytes.rs
@@ -352,8 +352,8 @@ impl Slice {
 unsafe impl CloneToUninit for Slice {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
-    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: we're just a wrapper around [u8]
-        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: we're just a transparent wrapper around [u8]
+        unsafe { self.inner.clone_to_uninit(dst) }
     }
 }
diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs
index b3834388df6..a4ad5966afe 100644
--- a/library/std/src/sys/os_str/wtf8.rs
+++ b/library/std/src/sys/os_str/wtf8.rs
@@ -275,8 +275,8 @@ impl Slice {
 unsafe impl CloneToUninit for Slice {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
-    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: we're just a wrapper around Wtf8
-        unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) }
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: we're just a transparent wrapper around Wtf8
+        unsafe { self.inner.clone_to_uninit(dst) }
     }
 }
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index 70f6981f717..17d15ed2e50 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -364,6 +364,26 @@ impl File {
         self.fsync()
     }
 
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
     pub fn truncate(&self, _size: u64) -> io::Result<()> {
         Err(Error::from_raw_os_error(22))
     }
diff --git a/library/std/src/sys/pal/hermit/io.rs b/library/std/src/sys/pal/hermit/io.rs
index aad1eef71e9..0424a1ac55a 100644
--- a/library/std/src/sys/pal/hermit/io.rs
+++ b/library/std/src/sys/pal/hermit/io.rs
@@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
 }
@@ -71,6 +71,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs
index bce9aa6d99c..776a96ff3b7 100644
--- a/library/std/src/sys/pal/solid/fs.rs
+++ b/library/std/src/sys/pal/solid/fs.rs
@@ -350,6 +350,26 @@ impl File {
         self.flush()
     }
 
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
     pub fn truncate(&self, _size: u64) -> io::Result<()> {
         unsupported()
     }
diff --git a/library/std/src/sys/pal/solid/io.rs b/library/std/src/sys/pal/solid/io.rs
index 4b1f788a492..9ef4b7049b6 100644
--- a/library/std/src/sys/pal/solid/io.rs
+++ b/library/std/src/sys/pal/solid/io.rs
@@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
 }
@@ -71,6 +71,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs
index f1f843a5f7a..96f99efb21e 100644
--- a/library/std/src/sys/pal/unix/fs.rs
+++ b/library/std/src/sys/pal/unix/fs.rs
@@ -1254,6 +1254,123 @@ impl File {
         }
     }
 
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    ))]
+    pub fn lock(&self) -> io::Result<()> {
+        cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX) })?;
+        return Ok(());
+    }
+
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    )))]
+    pub fn lock(&self) -> io::Result<()> {
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock() not supported"))
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    ))]
+    pub fn lock_shared(&self) -> io::Result<()> {
+        cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH) })?;
+        return Ok(());
+    }
+
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    )))]
+    pub fn lock_shared(&self) -> io::Result<()> {
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "lock_shared() not supported"))
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    ))]
+    pub fn try_lock(&self) -> io::Result<bool> {
+        let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) });
+        if let Err(ref err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                return Ok(false);
+            }
+        }
+        result?;
+        return Ok(true);
+    }
+
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    )))]
+    pub fn try_lock(&self) -> io::Result<bool> {
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock() not supported"))
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    ))]
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) });
+        if let Err(ref err) = result {
+            if err.kind() == io::ErrorKind::WouldBlock {
+                return Ok(false);
+            }
+        }
+        result?;
+        return Ok(true);
+    }
+
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    )))]
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported"))
+    }
+
+    #[cfg(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    ))]
+    pub fn unlock(&self) -> io::Result<()> {
+        cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_UN) })?;
+        return Ok(());
+    }
+
+    #[cfg(not(any(
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd",
+        target_vendor = "apple",
+    )))]
+    pub fn unlock(&self) -> io::Result<()> {
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "unlock() not supported"))
+    }
+
     pub fn truncate(&self, size: u64) -> io::Result<()> {
         let size: off64_t =
             size.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
diff --git a/library/std/src/sys/pal/unix/io.rs b/library/std/src/sys/pal/unix/io.rs
index 181c35a971e..0d5a152dc0d 100644
--- a/library/std/src/sys/pal/unix/io.rs
+++ b/library/std/src/sys/pal/unix/io.rs
@@ -33,7 +33,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
 }
@@ -71,6 +71,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
     }
diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs
index f0ebc767bad..4a992e32a91 100644
--- a/library/std/src/sys/pal/unix/pipe.rs
+++ b/library/std/src/sys/pal/unix/pipe.rs
@@ -23,6 +23,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
             target_os = "dragonfly",
             target_os = "freebsd",
             target_os = "hurd",
+            target_os = "illumos",
             target_os = "linux",
             target_os = "netbsd",
             target_os = "openbsd",
diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/pal/unsupported/fs.rs
index 474c9fe97d1..9585ec24f68 100644
--- a/library/std/src/sys/pal/unsupported/fs.rs
+++ b/library/std/src/sys/pal/unsupported/fs.rs
@@ -198,6 +198,26 @@ impl File {
         self.0
     }
 
+    pub fn lock(&self) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn try_lock(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        self.0
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        self.0
+    }
+
     pub fn truncate(&self, _size: u64) -> io::Result<()> {
         self.0
     }
diff --git a/library/std/src/sys/pal/unsupported/io.rs b/library/std/src/sys/pal/unsupported/io.rs
index 6372fca74e0..604735d32d5 100644
--- a/library/std/src/sys/pal/unsupported/io.rs
+++ b/library/std/src/sys/pal/unsupported/io.rs
@@ -15,7 +15,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         self.0
     }
 }
@@ -41,6 +41,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        self.0
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         self.0
     }
diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs
index 59ecc45b06a..3296c762cca 100644
--- a/library/std/src/sys/pal/wasi/fs.rs
+++ b/library/std/src/sys/pal/wasi/fs.rs
@@ -420,6 +420,26 @@ impl File {
         self.fd.datasync()
     }
 
+    pub fn lock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn try_lock(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        unsupported()
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        unsupported()
+    }
+
     pub fn truncate(&self, size: u64) -> io::Result<()> {
         self.fd.filestat_set_size(size)
     }
diff --git a/library/std/src/sys/pal/wasi/io.rs b/library/std/src/sys/pal/wasi/io.rs
index b7c2f03daa0..57f81bc6257 100644
--- a/library/std/src/sys/pal/wasi/io.rs
+++ b/library/std/src/sys/pal/wasi/io.rs
@@ -30,7 +30,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         unsafe { slice::from_raw_parts(self.vec.buf as *const u8, self.vec.buf_len) }
     }
 }
@@ -68,6 +68,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.buf_len) }
     }
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 192c95fd203..248ce3c9ff6 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2351,6 +2351,9 @@ Windows.Win32.Storage.FileSystem.GetFinalPathNameByHandleW
 Windows.Win32.Storage.FileSystem.GetFullPathNameW
 Windows.Win32.Storage.FileSystem.GetTempPathW
 Windows.Win32.Storage.FileSystem.INVALID_FILE_ATTRIBUTES
+Windows.Win32.Storage.FileSystem.LOCKFILE_EXCLUSIVE_LOCK
+Windows.Win32.Storage.FileSystem.LOCKFILE_FAIL_IMMEDIATELY
+Windows.Win32.Storage.FileSystem.LockFileEx
 Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE
 Windows.Win32.Storage.FileSystem.LPPROGRESS_ROUTINE_CALLBACK_REASON
 Windows.Win32.Storage.FileSystem.MAXIMUM_REPARSE_DATA_BUFFER_SIZE
@@ -2396,6 +2399,7 @@ Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAG_DIRECTORY
 Windows.Win32.Storage.FileSystem.SYMBOLIC_LINK_FLAGS
 Windows.Win32.Storage.FileSystem.SYNCHRONIZE
 Windows.Win32.Storage.FileSystem.TRUNCATE_EXISTING
+Windows.Win32.Storage.FileSystem.UnlockFile
 Windows.Win32.Storage.FileSystem.VOLUME_NAME_DOS
 Windows.Win32.Storage.FileSystem.VOLUME_NAME_GUID
 Windows.Win32.Storage.FileSystem.VOLUME_NAME_NONE
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 52444c2c009..19925e59dfe 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -65,6 +65,7 @@ windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinit
 windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
+windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
 windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
@@ -96,6 +97,7 @@ windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32)
 windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> BOOLEAN);
 windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> BOOLEAN);
+windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
 windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
@@ -2730,6 +2732,9 @@ pub struct LINGER {
     pub l_onoff: u16,
     pub l_linger: u16,
 }
+pub const LOCKFILE_EXCLUSIVE_LOCK: LOCK_FILE_FLAGS = 2u32;
+pub const LOCKFILE_FAIL_IMMEDIATELY: LOCK_FILE_FLAGS = 1u32;
+pub type LOCK_FILE_FLAGS = u32;
 pub type LPOVERLAPPED_COMPLETION_ROUTINE = Option<
     unsafe extern "system" fn(
         dwerrorcode: u32,
diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 5a9bfccc1fa..07e4f93a379 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -346,6 +346,120 @@ impl File {
         self.fsync()
     }
 
+    fn acquire_lock(&self, flags: c::LOCK_FILE_FLAGS) -> io::Result<()> {
+        unsafe {
+            let mut overlapped: c::OVERLAPPED = mem::zeroed();
+            let event = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null());
+            if event.is_null() {
+                return Err(io::Error::last_os_error());
+            }
+            overlapped.hEvent = event;
+            let lock_result = cvt(c::LockFileEx(
+                self.handle.as_raw_handle(),
+                flags,
+                0,
+                u32::MAX,
+                u32::MAX,
+                &mut overlapped,
+            ));
+
+            let final_result = match lock_result {
+                Ok(_) => Ok(()),
+                Err(err) => {
+                    if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
+                        // Wait for the lock to be acquired, and get the lock operation status.
+                        // This can happen asynchronously, if the file handle was opened for async IO
+                        let mut bytes_transferred = 0;
+                        cvt(c::GetOverlappedResult(
+                            self.handle.as_raw_handle(),
+                            &mut overlapped,
+                            &mut bytes_transferred,
+                            c::TRUE,
+                        ))
+                        .map(|_| ())
+                    } else {
+                        Err(err)
+                    }
+                }
+            };
+            c::CloseHandle(overlapped.hEvent);
+            final_result
+        }
+    }
+
+    pub fn lock(&self) -> io::Result<()> {
+        self.acquire_lock(c::LOCKFILE_EXCLUSIVE_LOCK)
+    }
+
+    pub fn lock_shared(&self) -> io::Result<()> {
+        self.acquire_lock(0)
+    }
+
+    pub fn try_lock(&self) -> io::Result<bool> {
+        let result = cvt(unsafe {
+            let mut overlapped = mem::zeroed();
+            c::LockFileEx(
+                self.handle.as_raw_handle(),
+                c::LOCKFILE_EXCLUSIVE_LOCK | c::LOCKFILE_FAIL_IMMEDIATELY,
+                0,
+                u32::MAX,
+                u32::MAX,
+                &mut overlapped,
+            )
+        });
+
+        match result {
+            Ok(_) => Ok(true),
+            Err(err)
+                if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
+                    || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
+            {
+                Ok(false)
+            }
+            Err(err) => Err(err),
+        }
+    }
+
+    pub fn try_lock_shared(&self) -> io::Result<bool> {
+        let result = cvt(unsafe {
+            let mut overlapped = mem::zeroed();
+            c::LockFileEx(
+                self.handle.as_raw_handle(),
+                c::LOCKFILE_FAIL_IMMEDIATELY,
+                0,
+                u32::MAX,
+                u32::MAX,
+                &mut overlapped,
+            )
+        });
+
+        match result {
+            Ok(_) => Ok(true),
+            Err(err)
+                if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
+                    || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
+            {
+                Ok(false)
+            }
+            Err(err) => Err(err),
+        }
+    }
+
+    pub fn unlock(&self) -> io::Result<()> {
+        // Unlock the handle twice because LockFileEx() allows a file handle to acquire
+        // both an exclusive and shared lock, in which case the documentation states that:
+        // "...two unlock operations are necessary to unlock the region; the first unlock operation
+        // unlocks the exclusive lock, the second unlock operation unlocks the shared lock"
+        cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) })?;
+        let result =
+            cvt(unsafe { c::UnlockFile(self.handle.as_raw_handle(), 0, 0, u32::MAX, u32::MAX) });
+        match result {
+            Ok(_) => Ok(()),
+            Err(err) if err.raw_os_error() == Some(c::ERROR_NOT_LOCKED as i32) => Ok(()),
+            Err(err) => Err(err),
+        }
+    }
+
     pub fn truncate(&self, size: u64) -> io::Result<()> {
         let info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as i64 };
         api::set_file_information_by_handle(self.handle.as_raw_handle(), &info).io_result()
diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs
index 1e7d02908f6..f2865d2ffc1 100644
--- a/library/std/src/sys/pal/windows/io.rs
+++ b/library/std/src/sys/pal/windows/io.rs
@@ -36,7 +36,7 @@ impl<'a> IoSlice<'a> {
     }
 
     #[inline]
-    pub fn as_slice(&self) -> &[u8] {
+    pub const fn as_slice(&self) -> &'a [u8] {
         unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
     }
 }
@@ -75,6 +75,11 @@ impl<'a> IoSliceMut<'a> {
     }
 
     #[inline]
+    pub const fn into_slice(self) -> &'a mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
+    }
+
+    #[inline]
     pub fn as_mut_slice(&mut self) -> &mut [u8] {
         unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
     }
diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs
index 19d4c94f450..666942bb8a1 100644
--- a/library/std/src/sys_common/wtf8.rs
+++ b/library/std/src/sys_common/wtf8.rs
@@ -1052,8 +1052,8 @@ impl Hash for Wtf8 {
 unsafe impl CloneToUninit for Wtf8 {
     #[inline]
     #[cfg_attr(debug_assertions, track_caller)]
-    unsafe fn clone_to_uninit(&self, dst: *mut Self) {
-        // SAFETY: we're just a wrapper around [u8]
-        unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) }
+    unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+        // SAFETY: we're just a transparent wrapper around [u8]
+        unsafe { self.bytes.clone_to_uninit(dst) }
     }
 }