What is "intrinsic indexing"?

I'm trying to understand how std::vec::Vec indexing works. I've traced the code to usize's SliceIndex trait implementation. It looks like it first dereferences the slice reference, then indexes it. But there doesn't seem to be index implementation on slice as value. What does "intrinsic indexing" mean?

“Intrinsic” means it is built in to the compiler, rather than being implemented in Rust library code.

Ah, I see. Thanks.

Do you know if this is documented somewhere? Or a website where I can look up all compiler built-in functionalities?

The documentation for the std::intrinsics module might be relevant, although slice indexing is not in exactly the same category as the functions there.

Not sure where you could get a list of them, but here's a few which I can think of, off the top of my head:

  • Arithmetic, if you try to dig into the arithmetic and binary arithmetic trait implementations for numbers in Rust, you'll get something like this:
    impl Add for usize {
        type Output = usize;
    
        #[inline]
        fn add(self, other: usize) -> usize {
            self + other
        }
    }
    
  • Dereferencing:
    impl<T: ?Sized> Deref for &T {
        type Target = T;
    
        fn deref(&self) -> &T {
            *self
        }
    }
    
  • Equality:
    impl PartialEq for usize {
        #[inline]
        fn eq(&self, other: &usize) -> bool {
            (*self) == (*other)
        }
        #[inline]
        fn ne(&self, other: &usize) -> bool {
            (*self) != (*other)
        }
    }
    
  • Safe Function pointers implement the Fn* traits regardless of the number or type of arguments. It is such a special implementation, that there is no "code" for the implementation of such, and asking whether fn() implements Fn() is done in compiler code, rather than libstd.
    • This additionally applies to closures, generators, and Futures, where user-generated anonymous types are given a set of traits that they implement.
  • Casting types to trait objects, although it does not have a trait-equivalent, is done in compiler code:
    let x = 3;
    let y: &dyn Debug = &x;
    
  • Boxing objects is done with a special box keyword:
    impl<T> Box<T> {
        #[inline(always)]
        pub fn new(x: T) -> Self {
            box x
        }
    }
    
  • Additionally, although less of an intrinsic, is the use of auto traits, where in the compiler will automatically implement them for any type as long as all values contained within that type implement it as well.
6 Likes