about summary refs log tree commit diff
path: root/library/core/src/ops/index.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/core/src/ops/index.rs')
-rw-r--r--library/core/src/ops/index.rs172
1 files changed, 172 insertions, 0 deletions
diff --git a/library/core/src/ops/index.rs b/library/core/src/ops/index.rs
new file mode 100644
index 00000000000..763b33606fe
--- /dev/null
+++ b/library/core/src/ops/index.rs
@@ -0,0 +1,172 @@
+/// Used for indexing operations (`container[index]`) in immutable contexts.
+///
+/// `container[index]` is actually syntactic sugar for `*container.index(index)`,
+/// but only when used as an immutable value. If a mutable value is requested,
+/// [`IndexMut`] is used instead. This allows nice things such as
+/// `let value = v[index]` if the type of `value` implements [`Copy`].
+///
+/// [`IndexMut`]: ../../std/ops/trait.IndexMut.html
+/// [`Copy`]: ../../std/marker/trait.Copy.html
+///
+/// # Examples
+///
+/// The following example implements `Index` on a read-only `NucleotideCount`
+/// container, enabling individual counts to be retrieved with index syntax.
+///
+/// ```
+/// use std::ops::Index;
+///
+/// enum Nucleotide {
+///     A,
+///     C,
+///     G,
+///     T,
+/// }
+///
+/// struct NucleotideCount {
+///     a: usize,
+///     c: usize,
+///     g: usize,
+///     t: usize,
+/// }
+///
+/// impl Index<Nucleotide> for NucleotideCount {
+///     type Output = usize;
+///
+///     fn index(&self, nucleotide: Nucleotide) -> &Self::Output {
+///         match nucleotide {
+///             Nucleotide::A => &self.a,
+///             Nucleotide::C => &self.c,
+///             Nucleotide::G => &self.g,
+///             Nucleotide::T => &self.t,
+///         }
+///     }
+/// }
+///
+/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12};
+/// assert_eq!(nucleotide_count[Nucleotide::A], 14);
+/// assert_eq!(nucleotide_count[Nucleotide::C], 9);
+/// assert_eq!(nucleotide_count[Nucleotide::G], 10);
+/// assert_eq!(nucleotide_count[Nucleotide::T], 12);
+/// ```
+#[lang = "index"]
+#[rustc_on_unimplemented(
+    message = "the type `{Self}` cannot be indexed by `{Idx}`",
+    label = "`{Self}` cannot be indexed by `{Idx}`"
+)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "]")]
+#[doc(alias = "[")]
+#[doc(alias = "[]")]
+pub trait Index<Idx: ?Sized> {
+    /// The returned type after indexing.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    type Output: ?Sized;
+
+    /// Performs the indexing (`container[index]`) operation.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[track_caller]
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+/// Used for indexing operations (`container[index]`) in mutable contexts.
+///
+/// `container[index]` is actually syntactic sugar for
+/// `*container.index_mut(index)`, but only when used as a mutable value. If
+/// an immutable value is requested, the [`Index`] trait is used instead. This
+/// allows nice things such as `v[index] = value`.
+///
+/// [`Index`]: ../../std/ops/trait.Index.html
+///
+/// # Examples
+///
+/// A very simple implementation of a `Balance` struct that has two sides, where
+/// each can be indexed mutably and immutably.
+///
+/// ```
+/// use std::ops::{Index,IndexMut};
+///
+/// #[derive(Debug)]
+/// enum Side {
+///     Left,
+///     Right,
+/// }
+///
+/// #[derive(Debug, PartialEq)]
+/// enum Weight {
+///     Kilogram(f32),
+///     Pound(f32),
+/// }
+///
+/// struct Balance {
+///     pub left: Weight,
+///     pub right: Weight,
+/// }
+///
+/// impl Index<Side> for Balance {
+///     type Output = Weight;
+///
+///     fn index(&self, index: Side) -> &Self::Output {
+///         println!("Accessing {:?}-side of balance immutably", index);
+///         match index {
+///             Side::Left => &self.left,
+///             Side::Right => &self.right,
+///         }
+///     }
+/// }
+///
+/// impl IndexMut<Side> for Balance {
+///     fn index_mut(&mut self, index: Side) -> &mut Self::Output {
+///         println!("Accessing {:?}-side of balance mutably", index);
+///         match index {
+///             Side::Left => &mut self.left,
+///             Side::Right => &mut self.right,
+///         }
+///     }
+/// }
+///
+/// let mut balance = Balance {
+///     right: Weight::Kilogram(2.5),
+///     left: Weight::Pound(1.5),
+/// };
+///
+/// // In this case, `balance[Side::Right]` is sugar for
+/// // `*balance.index(Side::Right)`, since we are only *reading*
+/// // `balance[Side::Right]`, not writing it.
+/// assert_eq!(balance[Side::Right], Weight::Kilogram(2.5));
+///
+/// // However, in this case `balance[Side::Left]` is sugar for
+/// // `*balance.index_mut(Side::Left)`, since we are writing
+/// // `balance[Side::Left]`.
+/// balance[Side::Left] = Weight::Kilogram(3.0);
+/// ```
+#[lang = "index_mut"]
+#[rustc_on_unimplemented(
+    on(
+        _Self = "&str",
+        note = "you can use `.chars().nth()` or `.bytes().nth()`
+see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+    ),
+    on(
+        _Self = "str",
+        note = "you can use `.chars().nth()` or `.bytes().nth()`
+see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+    ),
+    on(
+        _Self = "std::string::String",
+        note = "you can use `.chars().nth()` or `.bytes().nth()`
+see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+    ),
+    message = "the type `{Self}` cannot be mutably indexed by `{Idx}`",
+    label = "`{Self}` cannot be mutably indexed by `{Idx}`"
+)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
+pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
+    /// Performs the mutable indexing (`container[index]`) operation.
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[track_caller]
+    fn index_mut(&mut self, index: Idx) -> &mut Self::Output;
+}