Deep into the RUST Standard Library Kernel

intrinsic Library of RUST

Intrinsics is built in by the compiler and provided to other modules. For inherent functions, there is no need to ask how to implement them. Just understand their functions and use them when needed
. The internal library of the memory part has been introduced in the memory library chapter above. This section gives a brief introduction to other parts

intrinsic atomic operation function

The atomic operation function ensures that the data operated in the function will not be operated by other instructions in the atomic operation function. Generally, these functions directly correspond to the atomic instructions of the CPU and are implemented by assembly. Atomic in the intrinsic library_ XXX and atomic_xxx_ Functions of type XXX are atomic operation functions. Atomic operation functions are mainly used for critical protection in concurrent programming, and are the basis of other critical protection mechanisms, such as Mutex, RWlock, etc.

Mathematical function and bit operation function

Various integer and floating-point mathematical functions. This part is placed in intrinsic s mainly because modern CPU s have a lot of support for floating-point computing. These mathematical functions are implemented by assembly language, which is more efficient, so it is necessary to implement them by compiler.

Intronic Instruction Optimization and debugging function

Assertion class: assert_ Function of type XXXX
Function stack: caller_location

Summary

Intrinsics library is a means to complete the cross CPU architecture from the compiler level. Intrinsics is usually encapsulated by the upper library. However, in operating system programming and framework programming, there will still be an inevitable need for contact.

Basic Trait of RUST standard library

The behavior definition and Trait are implemented directly for generics in RUST

For example:

//Implement borrow < T > trail for all types
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T {
        self
    }
}
//Implement Receiver Trait for all reference types
impl<T: ?Sized> Receiver for &T {}

//Implement Receiver Trait for all mutable reference types
impl<T: ?Sized> Receiver for &mut T {}

//Implement clone trail for all native immutable pointer types
impl<T: ?Sized> Clone for *const T {
     fn clone(&self) -> Self {
         *self
     }
 }
//Implement clone trail for native variable pointer types
impl<T: ?Sized> Clone for *mut T {
     fn clone(&self) -> Self {
         *self
     }
}

//Implement asref < [T] > trail for slice type [T]
impl<T> AsRef<[T]> for [T] {
    fn as_ref(&self) -> &[T] {
        self
    }
}


// The behavior of the slice is the fragment of the specific implementation
// [T;N] represents array and [T] represents slice. Basically, the input characters can'T be simplified any more.
// The following is a unified behavior for all slice types. Slice types can be considered as references to native arrays in c++/java,
impl<T> [T] {
    pub const fn len(&self) -> usize {
        unsafe { crate::ptr::PtrRepr { const_ptr: self }.components.metadata }
    }

    pub const fn is_empty(&self) -> bool {
        self.len() == 0
    }
    
    //The following code shows the simplicity and comprehensiveness of the RUST code
    pub const fn first(&self) -> Option<&T> {
        if let [first, ..] = self { Some(first) } else { None }
    }

    pub const fn split_first(&self) -> Option<(&T, &[T])> {
        if let [first, tail @ ..] = self { Some((first, tail)) } else { None }
    }

    pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) {
        // Compared with C/C++/Java, the following code is a dream for programmers
        unsafe { (self.get_unchecked(..mid), self.get_unchecked(mid..)) }
    }
    ...
    ...
}

//Native pointers are fragments of concrete event behavior
impl<T: ?Sized> *const T {
    pub const fn is_null(self) -> bool {
        (self as *const u8).guaranteed_eq(null())
    }

    /// Casts to a pointer of another type.
    pub const fn cast<U>(self) -> *const U {
        self as _
    }

    pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
        if self.is_null() { None } else { unsafe { Some(&*self) } }
    }
    ...
    ...
}

//Native array pointer concrete behavior implementation fragment. Note that the native array pointer is also a native pointer,
//The function with the same name of * const T should not be implemented here.
impl<T> *const [T] {
    pub const fn len(self) -> usize {
        metadata(self)
    }

    pub const fn as_ptr(self) -> *const T {
        self as *const T
    }
    ...
    ...
}
// Implement partialeq < & b > trail for & A, if a implements partialeq < b >
impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
    where
        A: PartialEq<B>,
 {
     fn eq(&self, other: &&B) -> bool {
         PartialEq::eq(*self, *other)
     }
     fn ne(&self, other: &&B) -> bool {
         PartialEq::ne(*self, *other)
     }
}

When implementing behaviors or traits, you can implement specific behaviors and traits for restricted generics. The restrictions of generics include: unlimited, native pointer (variable / immutable) type of generics, reference (variable / immutable) type of generics, array type of generics, slice type of generics, slice reference (variable / immutable) type of generics, tuple (variable / immutable) type of generics, function type, trail restriction, etc.
When you implement behavior and Trait for a type structure that has generics, you can also implement specific behavior and Trait for restricted generics.

Compiler built-in trail code analysis

Generally, there are not many built-in trail codes. Most of the contents in the codes are the reference documents of trail. This section mainly focuses on some less involved contents in the official tutorials and documents.

//Send Trait
pub unsafe auto trait Send {
    // empty.
}
//Send trail is not supported for native pointers
impl<T: ?Sized> !Send for *const T {}
impl<T: ?Sized> !Send for *mut T {}

mod impls {
    // The type that implements Sync is immutable, and the reference supports Send
    unsafe impl<T: Sync + ?Sized> Send for &T {}
    // The type variable reference of the type that implements Send supports Send
    unsafe impl<T: Send + ?Sized> Send for &mut T {}
}

// Sync Trait
pub unsafe auto trait Sync {
    // Empty
}
//Sync trail is not supported for native pointers
impl<T: ?Sized> !Sync for *const T {}
impl<T: ?Sized> !Sync for *mut T {}

pub trait Sized {
    // Empty.
}

//If a Sized type is to be converted to a dynamic size type, it must implement unsize train
//For example, [T;N] implements unsize < [t] >
pub trait Unsize<T: ?Sized> {
    // Empty.
}

//It is mainly used for pattern matching. If a structure implements PartialEq, the Trait will be implemented automatically.
//It is speculated that this structure should be memory bit comparison
pub trait StructuralPartialEq {
    // Empty.
}

//It is mainly used for pattern matching. If a structure implements Eq, the Trait will be implemented automatically.
pub trait StructuralEq {
    // Empty.
}

//Copy, omitted
pub trait Copy: Clone {
    // Empty.
}

//Unified implementation of native type support for copy trail
mod copy_impls {

    use super::Copy;

    macro_rules! impl_copy {
        ($($t:ty)*) => {
            $(
                impl Copy for $t {}
            )*
        }
    }

    impl_copy! {
        usize u8 u16 u32 u64 u128
        isize i8 i16 i32 i64 i128
        f32 f64
        bool char
    }

    impl Copy for ! {}

    impl<T: ?Sized> Copy for *const T {}

    impl<T: ?Sized> Copy for *mut T {}

    //&Mut t does not support Copy to ensure the borrowing rules of RUST
    impl<T: ?Sized> Copy for &T {}
}

//Phantom data is used to make a mark in the type structure, marking some type attributes that need but do not have to have entities
//For example, phantom data, please refer to the standard library for details. 
//PhantomData is a unit structure. The variable name of the unit structure is the type name of the unit structure.
//Therefore, you can directly use phantom data when using it, and the compiler will automatically bring in the type instantiation information of generic types
pub struct PhantomData<T: ?Sized>;

ops operator train code analysis

In RUST, all operation symbols can be overloaded.

A little rule

In the overloaded function, if the overloaded symbol appears, the compiler uses the specified default operation. For example:

        impl const BitAnd for u8 {
            type Output = u8;
            //The & symbol inside the following function will no longer cause overloading, which is the default bitwise and operation of the compiler.
            fn bitand(self, rhs: u8) -> u8 { self & u8 }
        }

Mathematical operator train

Easy to understand, slightly

Bitwise operator train

Easy to understand, slightly

Relational operator train

The code and analysis are as follows

//Partial equality of type structures is allowed
pub trait PartialEq<Rhs: ?Sized = Self> {
    ///"= =" overload behavior
    fn eq(&self, other: &Rhs) -> bool;

    /// `!=`  Overload behavior
    fn ne(&self, other: &Rhs) -> bool {
        !self.eq(other)
    }
}

/// Derive macro generating an impl of the trait `PartialEq`.
///Procedure macros that implement the Derive property
pub macro PartialEq($item:item) {
    /* compiler built-in */
}

//Each attribute of a structure must be equal
pub trait Eq: PartialEq<Self> {
    fn assert_receiver_is_total_eq(&self) {}
}

///Procedure macros that implement the Derive property
pub macro Eq($item:item) {
    /* compiler built-in */
}

//A structure used to represent the result of a relationship
#[derive(Clone, Copy, PartialEq, Debug, Hash)]
#[repr(i8)]
pub enum Ordering {
    /// An ordering where a compared value is less than another.
    Less = -1,
    /// An ordering where a compared value is equal to another.
    Equal = 0,
    /// An ordering where a compared value is greater than another.
    Greater = 1,
}

impl Ordering {
    pub const fn is_eq(self) -> bool {
        matches!(self, Equal)
    }
    
    //The implementation of the following function body is omitted
    pub const fn is_ne(self) -> bool 
    pub const fn is_lt(self) -> bool 
    pub const fn is_gt(self) -> bool 
    pub const fn is_le(self) -> bool
    pub const fn is_ge(self) -> bool

    //Reverse operation
    pub const fn reverse(self) -> Ordering {
        match self {
            Less => Greater,
            Equal => Equal,
            Greater => Less,
        }
    }

    //Used to simplify code and better support functional programming
    //give an example:
    // let x: (i64, i64, i64) = (1, 2, 7);
    // let y: (i64, i64, i64) = (1, 5, 3);
    // let result = x.0.cmp(&y.0).then(x.1.cmp(&y.1)).then(x.2.cmp(&y.2));
    pub const fn then(self, other: Ordering) -> Ordering {
        match self {
            Equal => other,
            _ => self,
        }
    }

    //Used to simplify code implementation and support functional programming
    pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
        match self {
            Equal => f(),
            _ => self,
        }
    }
}


// "<" ">" "> =" "< =" "operator overloaded structure
pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
    fn partial_cmp(&self, other: &Rhs) -> Option<Ordering>;

    // "<" operator overload
    fn lt(&self, other: &Rhs) -> bool {
        matches!(self.partial_cmp(other), Some(Less))
    }
    
    //"< =" operator overload
    fn le(&self, other: &Rhs) -> bool {
        // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
        !matches!(self.partial_cmp(other), None | Some(Greater))
    }

    //">" operator overload
    fn gt(&self, other: &Rhs) -> bool {
        matches!(self.partial_cmp(other), Some(Greater))
    }
    
    //"> =" operator overload
    fn ge(&self, other: &Rhs) -> bool {
        matches!(self.partial_cmp(other), Some(Greater | Equal))
    }
}

//Process macro to implement Derive
pub macro PartialOrd($item:item) {
    /* compiler built-in */
}

//Use the input closure comparison function to obtain the larger of the two values
pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
    match compare(&v1, &v2) {
        Ordering::Less | Ordering::Equal => v2,
        Ordering::Greater => v1,
    }
}

//Use the input closure comparison function to obtain the small one of the two values
pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
    match compare(&v1, &v2) {
        Ordering::Less | Ordering::Equal => v1,
        Ordering::Greater => v2,
    }
}

//The following code is easy to understand and omitted
pub trait Ord: Eq + PartialOrd<Self> {
    fn cmp(&self, other: &Self) -> Ordering;

    fn max(self, other: Self) -> Self
    where
        Self: Sized,
    {
        max_by(self, other, Ord::cmp)
    }

    fn min(self, other: Self) -> Self
    where
        Self: Sized,
    {
        min_by(self, other, Ord::cmp)
    }

    fn clamp(self, min: Self, max: Self) -> Self
    where
        Self: Sized,
    {
        assert!(min <= max);
        if self < min {
            min
        } else if self > max {
            max
        } else {
            self
        }
    }
}
//Implement Drive property procedure macro
pub macro Ord($item:item) {
    /* compiler built-in */
}

pub fn min<T: Ord>(v1: T, v2: T) -> T {
    v1.min(v2)
}

pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
    min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
}

pub fn max<T: Ord>(v1: T, v2: T) -> T {
    v1.max(v2)
}

pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
    max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
}


//For types that implement PartialOrd, implementing the inversion of an Ord is a
//Design pattern example of adapter
pub struct Reverse<T>(pub T);

impl<T: PartialOrd> PartialOrd for Reverse<T> {
    fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }

    fn lt(&self, other: &Self) -> bool {
        other.0 < self.0
    }
    ...
    ...
}

impl<T: Ord> Ord for Reverse<T> {
    fn cmp(&self, other: &Reverse<T>) -> Ordering {
        other.0.cmp(&self.0)
    }
    ...
}

impl<T: Clone> Clone for Reverse<T> {
    fn clone(&self) -> Reverse<T> {
        Reverse(self.0.clone())
    }

    fn clone_from(&mut self, other: &Self) {
        self.0.clone_from(&other.0)
    }
}


// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
mod impls {
    use crate::cmp::Ordering::{self, Equal, Greater, Less};
    use crate::hint::unreachable_unchecked;
    
    //Implementation of PartialEq on native types
    macro_rules! partial_eq_impl {
        ($($t:ty)*) => ($(
            impl PartialEq for $t {
                fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
                fn ne(&self, other: &$t) -> bool { (*self) != (*other) }
            }
        )*)
    }

    impl PartialEq for () {
        fn eq(&self, _other: &()) -> bool {
            true
        }
        fn ne(&self, _other: &()) -> bool {
            false
        }
    }

    partial_eq_impl! {
        bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64
    }

    // Eq, partialord, implementation of ord on native types, omitted
    ...
    ...
    
    impl PartialEq for ! {
        fn eq(&self, _: &!) -> bool {
            *self
        }
    }

    impl Eq for ! {}

    impl PartialOrd for ! {
        fn partial_cmp(&self, _: &!) -> Option<Ordering> {
            *self
        }
    }

    impl Ord for ! {
        fn cmp(&self, _: &!) -> Ordering {
            *self
        }
    }

    //After a realizes partialeq < b > and partialord < b >, partialeq < & b > and partialord < & b > are realized for & A
    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
    where
        A: PartialEq<B>,
    {
        fn eq(&self, other: &&B) -> bool {
            //Pay attention to this calling method. Self. Cannot be used at this time EQ call.
            //The eq method parameter is a reference
            PartialEq::eq(*self, *other)
        }
        fn ne(&self, other: &&B) -> bool {
            PartialEq::ne(*self, *other)
        }
    }
    impl<A: ?Sized, B: ?Sized> PartialOrd<&B> for &A
    where
        A: PartialOrd<B>,
    {
        fn partial_cmp(&self, other: &&B) -> Option<Ordering> {
            PartialOrd::partial_cmp(*self, *other)
        }
        fn lt(&self, other: &&B) -> bool {
            PartialOrd::lt(*self, *other)
        }
        ...
        ...
    }

    //If a implements ord trail, implement ord trail for & A
    impl<A: ?Sized> Ord for &A
    where
        A: Ord,
    {
        fn cmp(&self, other: &Self) -> Ordering {
            Ord::cmp(*self, *other)
        }
    }
    impl<A: ?Sized> Eq for &A where A: Eq {}

    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &mut A
    where
        A: PartialEq<B>,
    {
        fn eq(&self, other: &&mut B) -> bool {
            PartialEq::eq(*self, *other)
        }
        fn ne(&self, other: &&mut B) -> bool {
            PartialEq::ne(*self, *other)
        }
    }

    impl<A: ?Sized, B: ?Sized> PartialOrd<&mut B> for &mut A
    where
        A: PartialOrd<B>,
    {
        fn partial_cmp(&self, other: &&mut B) -> Option<Ordering> {
            PartialOrd::partial_cmp(*self, *other)
        }
        fn lt(&self, other: &&mut B) -> bool {
            PartialOrd::lt(*self, *other)
        }
        ...
        ...
    }
    impl<A: ?Sized> Ord for &mut A
    where
        A: Ord,
    {
        fn cmp(&self, other: &Self) -> Ordering {
            Ord::cmp(*self, *other)
        }
    }
    impl<A: ?Sized> Eq for &mut A where A: Eq {}

    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &A
    where
        A: PartialEq<B>,
    {
        fn eq(&self, other: &&mut B) -> bool {
            PartialEq::eq(*self, *other)
        }
        fn ne(&self, other: &&mut B) -> bool {
            PartialEq::ne(*self, *other)
        }
    }

    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &mut A
    where
        A: PartialEq<B>,
    {
        fn eq(&self, other: &&B) -> bool {
            PartialEq::eq(*self, *other)
        }
        fn ne(&self, other: &&B) -> bool {
            PartialEq::ne(*self, *other)
        }
    }
}

The operator overloading of relational operation is more complex than other mathematical operators and bit cloud algorithms, so the code is relatively complete. But its logic is still relatively simple.

? Operator train code analysis

? Operation is a foundation of functional programming supported by RUST. Even if it is not used for functional programming, the code can be greatly simplified.
For a function, when a type implements try trail. What can I do for this type? Operation simplification code.
Try trail is also an implementation of try... catch in RUST, but it is more simplified in the form of code. In addition, because it can return specific types, this implementation method is not limited to handling exceptions, but can be extended to other similar scenarios. In terms of code, you can also complete exception return processing through the behavior of return type, which is more flexible and makes the whole code logic more natural and simple.
Try train is defined as follows:

pub trait Try: FromResidual {
    /// The type of the value produced by `?` when *not* short-circuiting.
    /// ? The return value type of the normal end of the operator
    type Output;

    /// The type of the value passed to [`FromResidual::from_residual`]
    /// as part of `?` when short-circuiting.
    /// ? The value type returned by the operator in advance, which will be explained by examples later
    type Residual;

    /// Constructs the type from its `Output` type.
    ///Get the value of the original type from the return value type of Self::Output
    /// This should be implemented consistently with the `branch` method
    /// such that applying the `?` operator will get back the original value:
    ///This function must comply with the principles of the following code,
    /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`.
    ///Example:
    /// ```
    /// #![feature(try_trait_v2)]
    /// use std::ops::Try;
    ///
    /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
    /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));
    /// assert_eq!(
    ///     <std::ops::ControlFlow<String, _> as Try>::from_output(5),
    ///     std::ops::ControlFlow::Continue(5),
    /// );
    fn from_output(output: Self::Output) -> Self;

    ///The branch function will return ControlFlow, which determines whether the process continues or returns in advance
    ///Example:
    /// ```p
    /// #![feature(try_trait_v2)]
    /// use std::ops::{ControlFlow, Try};
    ///
    /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
    /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
    ///
    /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3));
    /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None));
    ///
    /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3));
    /// assert_eq!(
    ///     ControlFlow::<_, String>::Break(3).branch(),
    ///     ControlFlow::Break(ControlFlow::Break(3)),
    /// );
    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
}

pub trait FromResidual<R = <Self as Try>::Residual> {
    ///This function gets the original value from the value returned in advance
    ///
    /// This should be implemented consistently with the `branch` method such
    /// that applying the `?` operator will get back an equivalent residual:
    ///This function must conform to the principles of the following code
    /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
    ///Example:
    /// ```
    /// #![feature(try_trait_v2)]
    /// use std::ops::{ControlFlow, FromResidual};
    ///
    /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
    /// assert_eq!(Option::<String>::from_residual(None), None);
    /// assert_eq!(
    ///     ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),
    ///     ControlFlow::Break(5),
    /// );
    /// ```
    fn from_residual(residual: R) -> Self;
}

Try trail, right? Examples of operation support are as follows:

//no need? Operation code
 pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
     iter: impl Iterator<Item = T>,
     mut accum: A,
     mut f: impl FnMut(A, T) -> R,
 ) -> R {
     for x in iter {
         let cf = f(accum, x).branch();
         match cf {
             ControlFlow::Continue(a) => accum = a,
             ControlFlow::Break(r) => return R::from_residual(r),
         }
     }
     R::from_output(accum)
 }
// use? Operation code:
 fn simple_try_fold<A, T, R: Try<Output = A>>(
     iter: impl Iterator<Item = T>,
     mut accum: A,
     mut f: impl FnMut(A, T) -> R,
 ) -> R {
     for x in iter {
         accum = f(accum, x)?;
     }
     R::from_output(accum)
 }

From the above, it can be inferred that T? Indicates the following code

   match((T as Try).branch()) {
       ControlFlow::Continue(a) => a,
       ControlFlow::Break(r) => return (T as Try)::from_residual(r),
   }

The ControlFlow type code is as follows, which is mainly used to indicate the control process. Logically, it can be analogized to continue. The break keyword code is as follows:

pub enum ControlFlow<B, C = ()> {
    /// Move on to the next phase of the operation as normal.
    Continue(C),
    /// Exit the operation without running subsequent phases.
    Break(B),
    // Yes, the order of the variants doesn't match the type parameters.
    // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
    // is a no-op conversion in the `Try` implementation.
}


impl<B, C> ops::Try for ControlFlow<B, C> {
    type Output = C;
    // Convert:: invalid means that the type will not be used, which can be considered as ignoring the type,
    //For Residual, only ControlFlow::Break(B) will be used, so it is explicitly stated that this type will not be used with infinite
    type Residual = ControlFlow<B, convert::Infallible>;

    fn from_output(output: Self::Output) -> Self {
        ControlFlow::Continue(output)
    }

    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            ControlFlow::Continue(c) => ControlFlow::Continue(c),
            ControlFlow::Break(b) => ControlFlow::Break(ControlFlow::Break(b)),
        }
}

impl<B, C> ops::FromResidual for ControlFlow<B, C> {
    // Impossible means that the type will not be used
    fn from_residual(residual: ControlFlow<B, convert::Infallible>) -> Self {
        match residual {
            ControlFlow::Break(b) => ControlFlow::Break(b),
        }
    }
}

Try train implementation of Option:

impl<T> ops::Try for Option<T> {
    type Output = T;
    // Infallible is an error type, but the error will never occur. Here, you need to return None,
    // So you need Option, but you only need None. There will be no other, so we use invisible
    type Residual = Option<convert::Infallible>;

    fn from_output(output: Self::Output) -> Self {
        Some(output)
    }

    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
        match self {
            Some(v) => ControlFlow::Continue(v),
            None => ControlFlow::Break(None),
        }
    }
}

impl<T> const ops::FromResidual for Option<T> {
    #[inline]
    fn from_residual(residual: Option<convert::Infallible>) -> Self {
        match residual {
            None => None,
        }
    }
}

An iterator:: try_ Implementation of fold():

    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Output = B>,
    {
        let mut accum = init;
        while let Some(x) = self.next() {
            accum = f(accum, x)?;
        }
        //try keywordconverts accum to a variable of type R
        try { accum }
    }

Summary

With try train, programmers can implement custom types?, Provide a powerful means of functional programming, simplify the code and improve the understanding of the code.

Range operator code analysis

Range is the form of symbol..., start... End, start...,... End,... = end, start... = end

Range related boundary structure Bound

Source code:

pub enum Bound<T> {
    /// An inclusive bound.
    ///Boundary includes
    Included(T),
    /// An exclusive bound.
    ///Boundary does not include
    Excluded(T),
    /// An infinite endpoint. Indicates that there is no bound in this direction.
    ///Boundary does not exist
    Unbounded,
}

The value of the Include boundary contains, the value of the excluded boundary does not contain, and the value of the Unbounded boundary does not exist

RangeFull

.. Data structure.

Range<Idx>

start.. end data structure

RangeFrom<Idx>

start.. Data structure of

RangeTo<Idx>

.. end

RangeInclusive<Idx>

start..=end data structure

RangeToInclusive<Idx>

.. = end data structure

RangeBounds<T: ?Sized>

Trail implemented by all ranges.

pub trait RangeBounds<T: ?Sized> {
    ///Gets the starting value of the range
    ///
    ///Examples
    /// # fn main() {
    /// use std::ops::Bound::*;
    /// use std::ops::RangeBounds;
    ///
    /// assert_eq!((..10).start_bound(), Unbounded);
    /// assert_eq!((3..10).start_bound(), Included(&3));
    /// # }
    /// ```
    fn start_bound(&self) -> Bound<&T>;

    ///Gets the end value of the range
    ///Examples
    /// # fn main() {
    /// use std::ops::Bound::*;
    /// use std::ops::RangeBounds;
    ///
    /// assert_eq!((3..).end_bound(), Unbounded);
    /// assert_eq!((3..10).end_bound(), Excluded(&10));
    /// # }
    /// ```
    fn end_bound(&self) -> Bound<&T>;

    ///Whether the range includes a value
    ///Examples
    /// assert!( (3..5).contains(&4));
    /// assert!(!(3..5).contains(&2));
    ///
    /// assert!( (0.0..1.0).contains(&0.5));
    /// assert!(!(0.0..1.0).contains(&f32::NAN));
    /// assert!(!(0.0..f32::NAN).contains(&0.5));
    /// assert!(!(f32::NAN..1.0).contains(&0.5));
    fn contains<U>(&self, item: &U) -> bool
    where
        T: PartialOrd<U>,
        U: ?Sized + PartialOrd<T>,
    {
        (match self.start_bound() {
            Included(start) => start <= item,
            Excluded(start) => start < item,
            Unbounded => true,
        }) && (match self.end_bound() {
            Included(end) => item <= end,
            Excluded(end) => item < end,
            Unbounded => true,
        })
    }
}

RangeBounds implements RangeFull, rangeTo, rangeinclusive, rangetoinclusive, rangefrom and range structures. At the same time, the tuple of (Bound, Bound) is implemented.

Range independence

In fact, the Range operator alone is meaningless. It is mainly used in combination with Index operator or Iterator. In the subsequent Index operator and Iterator, we will study how Range is combined with them.

Summary

The Range type based on generics provides a very good syntax means. As long as a type supports sorting, you can define a Range type based on this type. Combined with Index and Iterator, it will efficiently realize the code with great impact.

Code analysis of Index operator of RUST

Array subscript [] is overloaded by index and indexmut. Array subscript overloading makes the program more readable. Two trails are defined as follows:

pub trait Index<Idx: ?Sized> {
    /// The returned type after indexing.
    type Output: ?Sized;

    ///If the parameter passed in exceeds the memory limit, panic will be triggered immediately
    fn index(&self, index: Idx) -> &Self::Output;
}

pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
    fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
}

Index implementation of slice data structure [T]

impl<T, I> ops::Index<I> for [T]
where
    I: SliceIndex<[T]>,
{
    type Output = I::Output;

    fn index(&self, index: I) -> &I::Output {
        index.index(self)
    }
}

impl<T, I> ops::IndexMut<I> for [T]
where
    I: SliceIndex<[T]>,
{
    fn index_mut(&mut self, index: I) -> &mut I::Output {
        index.index_mut(self)
    }
}
Need to rely on SliceIndex Trait realization[T]of ops::Index. This design mainly needs to be used SliceIndex Namely realize usize The subscript takes out a single element and implements it again Range Subscript extractor slice. 
The following is an example RUST Programming skills
mod private_slice_index {
    use super::ops;
    pub trait Sealed {}

    impl Sealed for usize {}
    impl Sealed for ops::Range<usize> {}
    impl Sealed for ops::RangeTo<usize> {}
    impl Sealed for ops::RangeFrom<usize> {}
    impl Sealed for ops::RangeFull {}
    impl Sealed for ops::RangeInclusive<usize> {}
    impl Sealed for ops::RangeToInclusive<usize> {}
    impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
}

pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
    /// The output type returned by methods.
    type Output: ?Sized;

    /// Returns a shared reference to the output at this location, if in
    /// bounds.
    fn get(self, slice: &T) -> Option<&Self::Output>;

    /// Returns a mutable reference to the output at this location, if in
    /// bounds.
    fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;

    /// Returns a shared reference to the output at this location, without
    /// performing any bounds checking.
    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
    /// is *[undefined behavior]* even if the resulting reference is not used.
    ///
    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
    unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;

    /// Returns a mutable reference to the output at this location, without
    /// performing any bounds checking.
    /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
    /// is *[undefined behavior]* even if the resulting reference is not used.
    ///
    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
    unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;

    /// Returns a shared reference to the output at this location, panicking
    /// if out of bounds.
    fn index(self, slice: &T) -> &Self::Output;

    /// Returns a mutable reference to the output at this location, panicking
    /// if out of bounds.
    fn index_mut(self, slice: &mut T) -> &mut Self::Output;
}

pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed
SliceIndex inherits Sealed, that is, the structure implementing SliceIndex must implement Sealed. But the module to which Sealed belongs is private_slice_index is not public, so SliceIndex cannot be inherited in essence and can only be used inside the file. This is a programming skill of RUST, so that even if trail is public, it can not be implemented elsewhere.

unsafe impl<T> SliceIndex<[T]> for usize {
    type Output = T;

    fn get(self, slice: &[T]) -> Option<&T> {
        // SAFETY: `self` is checked to be in bounds.
        if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
    }

    fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
        // SAFETY: `self` is checked to be in bounds.
        if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
    }

    unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
        // SAFETY: the caller guarantees that `slice` is not dangling, so it
        // cannot be longer than `isize::MAX`. They also guarantee that
        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
        // so the call to `add` is safe.
        unsafe { slice.as_ptr().add(self) }
    }

    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
        // SAFETY: see comments for `get_unchecked` above.
        unsafe { slice.as_mut_ptr().add(self) }
    }

    fn index(self, slice: &[T]) -> &T {
        // N. B. use intrinsic indexing. get should be used here, but it should be built-in support of the compiler. For efficiency, the built-in array subscript is directly used.
        &(*slice)[self]
    }

    fn index_mut(self, slice: &mut [T]) -> &mut T {
        // N.B., use intrinsic indexing
        &mut (*slice)[self]
    }
}

The above is the underlying implementation of ops::Index and ops::IndexMut for [T] to take out a single element with an unsigned number as a subscript. ptr must be applied to take out a single element from slice. RUST seems to have the following characteristics. If the symbol overloading function uses the symbol again, it will no longer overload the symbol and calculate directly

unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
    type Output = [T];

    #[inline]
    fn get(self, slice: &[T]) -> Option<&[T]> {
        if self.start > self.end || self.end > slice.len() {
            None
        } else {
            // SAFETY: `self` is checked to be valid and in bounds above.
            unsafe { Some(&*self.get_unchecked(slice)) }
        }
    }

    #[inline]
    fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
        if self.start > self.end || self.end > slice.len() {
            None
        } else {
            // SAFETY: `self` is checked to be valid and in bounds above.
            unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
        }
    }

    #[inline]
    unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
        // SAFETY: the caller guarantees that `slice` is not dangling, so it
        // cannot be longer than `isize::MAX`. They also guarantee that
        // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
        // so the call to `add` is safe.
        unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
    }

    #[inline]
    unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
        // SAFETY: see comments for `get_unchecked` above.
        unsafe {
            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
        }
    }

    #[inline]
    fn index(self, slice: &[T]) -> &[T] {
        if self.start > self.end {
            slice_index_order_fail(self.start, self.end);
        } else if self.end > slice.len() {
            slice_end_index_len_fail(self.end, slice.len());
        }
        // SAFETY: `self` is checked to be valid and in bounds above.
        unsafe { &*self.get_unchecked(slice) }
    }

    #[inline]
    fn index_mut(self, slice: &mut [T]) -> &mut [T] {
        if self.start > self.end {
            slice_index_order_fail(self.start, self.end);
        } else if self.end > slice.len() {
            slice_end_index_len_fail(self.end, slice.len());
        }
        // SAFETY: `self` is checked to be valid and in bounds above.
        unsafe { &mut *self.get_unchecked_mut(slice) }
    }
}

The above is an implementation of taking the sub slice from the slice with Range. The core is still PTR:: slice_ from_ raw_ Operation of parts. Others, such as RangeTo, are similar to Range.

ops::Index implementation of array data structure [T;N]

#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
impl<T, I, const N: usize> Index<I> for [T; N]
where
    [T]: Index<I>,
{
    type Output = <[T] as Index<I>>::Output;

    #[inline]
    fn index(&self, index: I) -> &Self::Output {
        Index::index(self as &[T], index)
    }
}

#[stable(feature = "index_trait_on_arrays", since = "1.50.0")]
impl<T, I, const N: usize> IndexMut<I> for [T; N]
where
    [T]: IndexMut<I>,
{
    #[inline]
    fn index_mut(&mut self, index: I) -> &mut Self::Output {
        IndexMut::index_mut(self as &mut [T], index)
    }
}

Above, self as & [T] is to convert [T;N] into slice [T], so the Index of the array is the Index implementation of [T]

Keywords: Back-end Rust

Added by phppucci on Wed, 02 Feb 2022 12:29:01 +0200