diff --git a/.lock b/.lock new file mode 100644 index 0000000..e69de29 diff --git a/crates.js b/crates.js new file mode 100644 index 0000000..7289900 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["memory_set"]; \ No newline at end of file diff --git a/help.html b/help.html new file mode 100644 index 0000000..5659f36 --- /dev/null +++ b/help.html @@ -0,0 +1 @@ +
Redirecting to ../../memory_set/struct.MemoryArea.html...
+ + + \ No newline at end of file diff --git a/memory_set/area/trait.MappingBackend.html b/memory_set/area/trait.MappingBackend.html new file mode 100644 index 0000000..3969c2c --- /dev/null +++ b/memory_set/area/trait.MappingBackend.html @@ -0,0 +1,11 @@ + + + + +Redirecting to ../../memory_set/trait.MappingBackend.html...
+ + + \ No newline at end of file diff --git a/memory_set/enum.MappingError.html b/memory_set/enum.MappingError.html new file mode 100644 index 0000000..ba007c0 --- /dev/null +++ b/memory_set/enum.MappingError.html @@ -0,0 +1,21 @@ +pub enum MappingError {
+ InvalidParam,
+ AlreadyExists,
+ BadState,
+}
Error type for memory mapping operations.
+Invalid parameter (e.g., addr
, size
, flags
, etc.)
The given range clashes with an existing.
+The backend page table is in a bad state.
+self
and other
values to be equal, and is used
+by ==
.Data structures and operations for managing memory mappings.
+It is useful to implement mmap
and munmap
.
use memory_addr::{va, va_range, VirtAddr};
+use memory_set::{MappingBackend, MemoryArea, MemorySet};
+
+const MAX_ADDR: usize = 0x10000;
+
+/// A mock memory flags.
+type MockFlags = u8;
+/// A mock page table, which is a simple array that maps addresses to flags.
+type MockPageTable = [MockFlags; MAX_ADDR];
+
+/// A mock mapping backend that manipulates the page table on `map` and `unmap`.
+#[derive(Clone)]
+struct MockBackend;
+
+let mut pt = [0; MAX_ADDR];
+let mut memory_set = MemorySet::<MockFlags, MockPageTable, MockBackend>::new();
+
+// Map [0x1000..0x5000).
+memory_set.map(
+ /* area: */ MemoryArea::new(va!(0x1000), 0x4000, 1, MockBackend),
+ /* page_table: */ &mut pt,
+ /* unmap_overlap */ false,
+).unwrap();
+// Unmap [0x2000..0x4000), will split the area into two parts.
+memory_set.unmap(va!(0x2000), 0x2000, &mut pt).unwrap();
+
+let areas = memory_set.iter().collect::<Vec<_>>();
+assert_eq!(areas.len(), 2);
+assert_eq!(areas[0].va_range(), va_range!(0x1000..0x2000));
+assert_eq!(areas[1].va_range(), va_range!(0x4000..0x5000));
+
+// Underlying operations to do when manipulating mappings.
+impl MappingBackend<MockFlags, MockPageTable> for MockBackend {
+ fn map(&self, start: VirtAddr, size: usize, flags: MockFlags, pt: &mut MockPageTable) -> bool {
+ for entry in pt.iter_mut().skip(start.as_usize()).take(size) {
+ if *entry != 0 {
+ return false;
+ }
+ *entry = flags;
+ }
+ true
+ }
+
+ fn unmap(&self, start: VirtAddr, size: usize, pt: &mut MockPageTable) -> bool {
+ for entry in pt.iter_mut().skip(start.as_usize()).take(size) {
+ if *entry == 0 {
+ return false;
+ }
+ *entry = 0;
+ }
+ true
+ }
+}
MemoryArea
).Result
type with MappingError
as the error type.Redirecting to ../../memory_set/struct.MemorySet.html...
+ + + \ No newline at end of file diff --git a/memory_set/sidebar-items.js b/memory_set/sidebar-items.js new file mode 100644 index 0000000..159f6d0 --- /dev/null +++ b/memory_set/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["MappingError"],"struct":["MemoryArea","MemorySet"],"trait":["MappingBackend"],"type":["MappingResult"]}; \ No newline at end of file diff --git a/memory_set/struct.MemoryArea.html b/memory_set/struct.MemoryArea.html new file mode 100644 index 0000000..545f772 --- /dev/null +++ b/memory_set/struct.MemoryArea.html @@ -0,0 +1,40 @@ +pub struct MemoryArea<F: Copy, P, B: MappingBackend<F, P>> { /* private fields */ }
A memory area represents a continuous range of virtual memory with the same +flags.
+The target physical memory frames are determined by MappingBackend
and
+may not be contiguous.
pub struct MemorySet<F: Copy, P, B: MappingBackend<F, P>> { /* private fields */ }
A container that maintains memory mappings (MemoryArea
).
Returns the iterator over all memory areas.
+Returns whether the given address range overlaps with any existing area.
+Finds the memory area that contains the given address.
+Finds a free area that can accommodate the given size.
+The search starts from the given hint
address, and the area should be
+within the given limit
range.
Returns the start address of the free area. Returns None
if no such
+area is found.
Add a new memory mapping.
+The mapping is represented by a MemoryArea
.
If the new area overlaps with any existing area, the behavior is
+determined by the unmap_overlap
parameter. If it is true
, the
+overlapped regions will be unmapped first. Otherwise, it returns an
+error.
Remove memory mappings within the given address range.
+All memory areas that are fully contained in the range will be removed +directly. If the area intersects with the boundary, it will be shrinked. +If the unmapped range is in the middle of an existing area, it will be +split into two areas.
+Remove all memory areas and the underlying mappings.
+pub trait MappingBackend<F: Copy, P>: Clone {
+ // Required methods
+ fn map(
+ &self,
+ start: VirtAddr,
+ size: usize,
+ flags: F,
+ page_table: &mut P,
+ ) -> bool;
+ fn unmap(&self, start: VirtAddr, size: usize, page_table: &mut P) -> bool;
+}
Underlying operations to do when manipulating mappings within the specific +memory area.
+The backend can be different for different memory areas. e.g., for linear +mappings, the target physical address is known when it is added to the page +table. For lazy mappings, an empty mapping needs to be added to the page table +to trigger a page fault.
+pub type MappingResult<T = ()> = Result<T, MappingError>;
A Result
type with MappingError
as the error type.
enum MappingResult<T = ()> {
+ Ok(T),
+ Err(MappingError),
+}
addr
, size
, flags
, etc.)\nUnderlying operations to do when manipulating mappings …\nError type for memory mapping operations.\nA Result
type with MappingError
as the error type.\nA memory area represents a continuous range of virtual …\nA container that maintains memory mappings (MemoryArea
).\nContains the success value\nReturns the mapping backend of the memory area.\nRemove all memory areas and the underlying mappings.\nReturns the end address of the memory area.\nFinds the memory area that contains the given address.\nFinds a free area that can accommodate the given size.\nReturns the memory flags, e.g., the permission bits.\nReturns the argument unchanged.\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self)
.\nCalls U::from(self)
.\nCalls U::from(self)
.\nReturns true
if the memory set contains no memory areas.\nReturns the iterator over all memory areas.\nReturns the number of memory areas in the memory set.\nWhat to do when mapping a region within the area with the …\nAdd a new memory mapping.\nCreates a new memory area.\nCreates a new memory set.\nReturns whether the given address range overlaps with any …\nReturns the size of the memory area.\nReturns the start address of the memory area.\nWhat to do when unmaping a memory region within the area.\nRemove memory mappings within the given address range.\nReturns the virtual address range.")
\ No newline at end of file
diff --git a/settings.html b/settings.html
new file mode 100644
index 0000000..1f153cd
--- /dev/null
+++ b/settings.html
@@ -0,0 +1 @@
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +
use core::fmt;
+use core::marker::PhantomData;
+
+use memory_addr::{VirtAddr, VirtAddrRange};
+
+use crate::{MappingError, MappingResult};
+
+/// Underlying operations to do when manipulating mappings within the specific
+/// memory area.
+///
+/// The backend can be different for different memory areas. e.g., for linear
+/// mappings, the target physical address is known when it is added to the page
+/// table. For lazy mappings, an empty mapping needs to be added to the page table
+/// to trigger a page fault.
+pub trait MappingBackend<F: Copy, P>: Clone {
+ /// What to do when mapping a region within the area with the given flags.
+ fn map(&self, start: VirtAddr, size: usize, flags: F, page_table: &mut P) -> bool;
+ /// What to do when unmaping a memory region within the area.
+ fn unmap(&self, start: VirtAddr, size: usize, page_table: &mut P) -> bool;
+}
+
+/// A memory area represents a continuous range of virtual memory with the same
+/// flags.
+///
+/// The target physical memory frames are determined by [`MappingBackend`] and
+/// may not be contiguous.
+pub struct MemoryArea<F: Copy, P, B: MappingBackend<F, P>> {
+ va_range: VirtAddrRange,
+ flags: F,
+ backend: B,
+ _phantom: PhantomData<(F, P)>,
+}
+
+impl<F: Copy, P, B: MappingBackend<F, P>> MemoryArea<F, P, B> {
+ /// Creates a new memory area.
+ pub const fn new(start: VirtAddr, size: usize, flags: F, backend: B) -> Self {
+ Self {
+ va_range: VirtAddrRange::from_start_size(start, size),
+ flags,
+ backend,
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Returns the virtual address range.
+ pub const fn va_range(&self) -> VirtAddrRange {
+ self.va_range
+ }
+
+ /// Returns the memory flags, e.g., the permission bits.
+ pub const fn flags(&self) -> F {
+ self.flags
+ }
+
+ /// Returns the start address of the memory area.
+ pub const fn start(&self) -> VirtAddr {
+ self.va_range.start
+ }
+
+ /// Returns the end address of the memory area.
+ pub const fn end(&self) -> VirtAddr {
+ self.va_range.end
+ }
+
+ /// Returns the size of the memory area.
+ pub const fn size(&self) -> usize {
+ self.va_range.size()
+ }
+
+ /// Returns the mapping backend of the memory area.
+ pub const fn backend(&self) -> &B {
+ &self.backend
+ }
+}
+
+impl<F: Copy, P, B: MappingBackend<F, P>> MemoryArea<F, P, B> {
+ /// Maps the whole memory area in the page table.
+ pub(crate) fn map_area(&self, page_table: &mut P) -> MappingResult {
+ self.backend
+ .map(self.start(), self.size(), self.flags, page_table)
+ .then_some(())
+ .ok_or(MappingError::BadState)
+ }
+
+ /// Unmaps the whole memory area in the page table.
+ pub(crate) fn unmap_area(&self, page_table: &mut P) -> MappingResult {
+ self.backend
+ .unmap(self.start(), self.size(), page_table)
+ .then_some(())
+ .ok_or(MappingError::BadState)
+ }
+
+ /// Shrinks the memory area at the left side.
+ ///
+ /// The start address of the memory area is increased by `new_size`. The
+ /// shrunk part is unmapped.
+ pub(crate) fn shrink_left(&mut self, new_size: usize, page_table: &mut P) -> MappingResult {
+ let unmap_size = self.size() - new_size;
+ if !self.backend.unmap(self.start(), unmap_size, page_table) {
+ return Err(MappingError::BadState);
+ }
+ self.va_range.start += unmap_size;
+ Ok(())
+ }
+
+ /// Shrinks the memory area at the right side.
+ ///
+ /// The end address of the memory area is decreased by `new_size`. The
+ /// shrunk part is unmapped.
+ pub(crate) fn shrink_right(&mut self, new_size: usize, page_table: &mut P) -> MappingResult {
+ let unmap_size = self.size() - new_size;
+ if !self
+ .backend
+ .unmap(self.start() + new_size, unmap_size, page_table)
+ {
+ return Err(MappingError::BadState);
+ }
+ self.va_range.end -= unmap_size;
+ Ok(())
+ }
+
+ /// Splits the memory area at the given position.
+ ///
+ /// The original memory area is shrunk to the left part, and the right part
+ /// is returned.
+ ///
+ /// Returns `None` if the given position is not in the memory area, or one
+ /// of the parts is empty after splitting.
+ pub(crate) fn split(&mut self, pos: VirtAddr) -> Option<Self> {
+ let start = self.start();
+ let end = self.end();
+ if start < pos && pos < end {
+ let new_area = Self::new(
+ pos,
+ end.as_usize() - pos.as_usize(),
+ self.flags,
+ self.backend.clone(),
+ );
+ self.va_range.end = pos;
+ Some(new_area)
+ } else {
+ None
+ }
+ }
+}
+
+impl<F, P, B: MappingBackend<F, P>> fmt::Debug for MemoryArea<F, P, B>
+where
+ F: fmt::Debug + Copy,
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("MemoryArea")
+ .field("va_range", &self.va_range)
+ .field("flags", &self.flags)
+ .finish()
+ }
+}
+
#![cfg_attr(not(test), no_std)]
+#![doc = include_str!("../README.md")]
+
+extern crate alloc;
+
+mod area;
+mod set;
+
+#[cfg(test)]
+mod tests;
+
+pub use self::area::{MappingBackend, MemoryArea};
+pub use self::set::MemorySet;
+
+/// Error type for memory mapping operations.
+#[derive(Debug, Eq, PartialEq)]
+pub enum MappingError {
+ /// Invalid parameter (e.g., `addr`, `size`, `flags`, etc.)
+ InvalidParam,
+ /// The given range clashes with an existing.
+ AlreadyExists,
+ /// The backend page table is in a bad state.
+ BadState,
+}
+
+/// A [`Result`] type with [`MappingError`] as the error type.
+pub type MappingResult<T = ()> = Result<T, MappingError>;
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +
use alloc::collections::BTreeMap;
+use core::fmt;
+
+use memory_addr::{VirtAddr, VirtAddrRange};
+
+use crate::{MappingBackend, MappingError, MappingResult, MemoryArea};
+
+/// A container that maintains memory mappings ([`MemoryArea`]).
+pub struct MemorySet<F: Copy, P, B: MappingBackend<F, P>> {
+ areas: BTreeMap<VirtAddr, MemoryArea<F, P, B>>,
+}
+
+impl<F: Copy, P, B: MappingBackend<F, P>> MemorySet<F, P, B> {
+ /// Creates a new memory set.
+ pub const fn new() -> Self {
+ Self {
+ areas: BTreeMap::new(),
+ }
+ }
+
+ /// Returns the number of memory areas in the memory set.
+ pub fn len(&self) -> usize {
+ self.areas.len()
+ }
+
+ /// Returns `true` if the memory set contains no memory areas.
+ pub fn is_empty(&self) -> bool {
+ self.areas.is_empty()
+ }
+
+ /// Returns the iterator over all memory areas.
+ pub fn iter(&self) -> impl Iterator<Item = &MemoryArea<F, P, B>> {
+ self.areas.values()
+ }
+
+ /// Returns whether the given address range overlaps with any existing area.
+ pub fn overlaps(&self, range: VirtAddrRange) -> bool {
+ if let Some((_, before)) = self.areas.range(..range.start).last() {
+ if before.va_range().overlaps(range) {
+ return true;
+ }
+ }
+ if let Some((_, after)) = self.areas.range(range.start..).next() {
+ if after.va_range().overlaps(range) {
+ return true;
+ }
+ }
+ false
+ }
+
+ /// Finds the memory area that contains the given address.
+ pub fn find(&self, addr: VirtAddr) -> Option<&MemoryArea<F, P, B>> {
+ let candidate = self.areas.range(..=addr).last().map(|(_, a)| a);
+ candidate.filter(|a| a.va_range().contains(addr))
+ }
+
+ /// Finds a free area that can accommodate the given size.
+ ///
+ /// The search starts from the given `hint` address, and the area should be
+ /// within the given `limit` range.
+ ///
+ /// Returns the start address of the free area. Returns `None` if no such
+ /// area is found.
+ pub fn find_free_area(
+ &self,
+ hint: VirtAddr,
+ size: usize,
+ limit: VirtAddrRange,
+ ) -> Option<VirtAddr> {
+ // brute force: try each area's end address as the start.
+ let mut last_end = hint.max(limit.start);
+ for (addr, area) in self.areas.iter() {
+ if last_end + size <= *addr {
+ return Some(last_end);
+ }
+ last_end = area.end();
+ }
+ if last_end + size <= limit.end {
+ Some(last_end)
+ } else {
+ None
+ }
+ }
+
+ /// Add a new memory mapping.
+ ///
+ /// The mapping is represented by a [`MemoryArea`].
+ ///
+ /// If the new area overlaps with any existing area, the behavior is
+ /// determined by the `unmap_overlap` parameter. If it is `true`, the
+ /// overlapped regions will be unmapped first. Otherwise, it returns an
+ /// error.
+ pub fn map(
+ &mut self,
+ area: MemoryArea<F, P, B>,
+ page_table: &mut P,
+ unmap_overlap: bool,
+ ) -> MappingResult {
+ if area.va_range().is_empty() {
+ return Err(MappingError::InvalidParam);
+ }
+
+ if self.overlaps(area.va_range()) {
+ if unmap_overlap {
+ self.unmap(area.start(), area.size(), page_table)?;
+ } else {
+ return Err(MappingError::AlreadyExists);
+ }
+ }
+
+ area.map_area(page_table)?;
+ assert!(self.areas.insert(area.start(), area).is_none());
+ Ok(())
+ }
+
+ /// Remove memory mappings within the given address range.
+ ///
+ /// All memory areas that are fully contained in the range will be removed
+ /// directly. If the area intersects with the boundary, it will be shrinked.
+ /// If the unmapped range is in the middle of an existing area, it will be
+ /// split into two areas.
+ pub fn unmap(&mut self, start: VirtAddr, size: usize, page_table: &mut P) -> MappingResult {
+ let range = VirtAddrRange::from_start_size(start, size);
+ let end = range.end;
+ if range.is_empty() {
+ return Ok(());
+ }
+
+ // Unmap entire areas that are contained by the range.
+ self.areas.retain(|_, area| {
+ if area.va_range().contained_in(range) {
+ area.unmap_area(page_table).unwrap();
+ false
+ } else {
+ true
+ }
+ });
+
+ // Shrink right if the area intersects with the left boundary.
+ if let Some((before_start, before)) = self.areas.range_mut(..start).last() {
+ let before_end = before.end();
+ if before_end > start {
+ if before_end <= end {
+ // the unmapped area is at the end of `before`.
+ before.shrink_right(start.as_usize() - before_start.as_usize(), page_table)?;
+ } else {
+ // the unmapped area is in the middle `before`, need to split.
+ let right_part = before.split(end).unwrap();
+ before.shrink_right(start.as_usize() - before_start.as_usize(), page_table)?;
+ assert_eq!(right_part.start(), end);
+ self.areas.insert(end, right_part);
+ }
+ }
+ }
+
+ // Shrink left if the area intersects with the right boundary.
+ if let Some((&after_start, after)) = self.areas.range_mut(start..).next() {
+ let after_end = after.end();
+ if after_start < end {
+ // the unmapped area is at the start of `after`.
+ let mut new_area = self.areas.remove(&after_start).unwrap();
+ new_area.shrink_left(after_end.as_usize() - end.as_usize(), page_table)?;
+ assert_eq!(new_area.start(), end);
+ self.areas.insert(end, new_area);
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Remove all memory areas and the underlying mappings.
+ pub fn clear(&mut self, page_table: &mut P) -> MappingResult {
+ for (_, area) in self.areas.iter() {
+ area.unmap_area(page_table)?;
+ }
+ self.areas.clear();
+ Ok(())
+ }
+}
+
+impl<F: Copy + fmt::Debug, P, B: MappingBackend<F, P>> fmt::Debug for MemorySet<F, P, B> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_list().entries(self.areas.values()).finish()
+ }
+}
+
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ -> vec
or String, enum:Cow -> bool
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for functions that accept or return \
+ slices and \
+ arrays by writing \
+ square brackets (e.g., -> [u8]
or [] -> Option
)","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="${value.replaceAll(" ", " ")}
`}else{error[index]=value}});output+=`Takes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
occur, a\ncontainer with the values of each Result
is returned.
Here is an example which increments every integer in a vector,\nchecking for overflow:
\n\nlet v = vec![1, 2];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n x.checked_add(1).ok_or(\"Overflow!\")\n).collect();\nassert_eq!(res, Ok(vec![2, 3]));
Here is another example that tries to subtract one from another list\nof integers, this time checking for underflow:
\n\nlet v = vec![1, 2, 0];\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32|\n x.checked_sub(1).ok_or(\"Underflow!\")\n).collect();\nassert_eq!(res, Err(\"Underflow!\"));
Here is a variation on the previous example, showing that no\nfurther elements are taken from iter
after the first Err
.
let v = vec![3, 2, 1, 10];\nlet mut shared = 0;\nlet res: Result<Vec<u32>, &'static str> = v.iter().map(|x: &u32| {\n shared += x;\n x.checked_sub(2).ok_or(\"Underflow!\")\n}).collect();\nassert_eq!(res, Err(\"Underflow!\"));\nassert_eq!(shared, 6);
Since the third element caused an underflow, no further elements were taken,\nso the final value of shared
is 6 (= 3 + 2 + 1
), not 16.
try_trait_v2
)Residual
type. Read moreReturns a consuming iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let x: Result<u32, &str> = Ok(5);\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, [5]);\n\nlet x: Result<u32, &str> = Err(\"nothing!\");\nlet v: Vec<u32> = x.into_iter().collect();\nassert_eq!(v, []);
self
and other
) and is used by the <=
\noperator. Read moreTakes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
\noccur, the product of all elements is returned.
This multiplies each number in a vector of strings,\nif a string could not be parsed the operation returns Err
:
let nums = vec![\"5\", \"10\", \"1\", \"2\"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert_eq!(total, Ok(100));\nlet nums = vec![\"5\", \"10\", \"one\", \"2\"];\nlet total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();\nassert!(total.is_err());
Maps a Result<&mut T, E>
to a Result<T, E>
by copying the contents of the\nOk
part.
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet copied = x.copied();\nassert_eq!(copied, Ok(12));
Maps a Result<&mut T, E>
to a Result<T, E>
by cloning the contents of the\nOk
part.
let mut val = 12;\nlet x: Result<&mut i32, i32> = Ok(&mut val);\nassert_eq!(x, Ok(&mut 12));\nlet cloned = x.cloned();\nassert_eq!(cloned, Ok(12));
Transposes a Result
of an Option
into an Option
of a Result
.
Ok(None)
will be mapped to None
.\nOk(Some(_))
and Err(_)
will be mapped to Some(Ok(_))
and Some(Err(_))
.
#[derive(Debug, Eq, PartialEq)]\nstruct SomeErr;\n\nlet x: Result<Option<i32>, SomeErr> = Ok(Some(5));\nlet y: Option<Result<i32, SomeErr>> = Some(Ok(5));\nassert_eq!(x.transpose(), y);
result_flattening
)Converts from Result<Result<T, E>, E>
to Result<T, E>
#![feature(result_flattening)]\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Ok(\"hello\"));\nassert_eq!(Ok(\"hello\"), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Ok(Err(6));\nassert_eq!(Err(6), x.flatten());\n\nlet x: Result<Result<&'static str, u32>, u32> = Err(6);\nassert_eq!(Err(6), x.flatten());
Flattening only removes one level of nesting at a time:
\n\n#![feature(result_flattening)]\nlet x: Result<Result<Result<&'static str, u32>, u32>, u32> = Ok(Ok(Ok(\"hello\")));\nassert_eq!(Ok(Ok(\"hello\")), x.flatten());\nassert_eq!(Ok(\"hello\"), x.flatten().flatten());
Returns true
if the result is Ok
and the value inside of it matches a predicate.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.is_ok_and(|x| x > 1), true);\n\nlet x: Result<u32, &str> = Ok(0);\nassert_eq!(x.is_ok_and(|x| x > 1), false);\n\nlet x: Result<u32, &str> = Err(\"hey\");\nassert_eq!(x.is_ok_and(|x| x > 1), false);
Returns true
if the result is Err
and the value inside of it matches a predicate.
use std::io::{Error, ErrorKind};\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, \"!\"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), true);\n\nlet x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, \"!\"));\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);\n\nlet x: Result<u32, Error> = Ok(123);\nassert_eq!(x.is_err_and(|x| x.kind() == ErrorKind::NotFound), false);
Converts from Result<T, E>
to Option<E>
.
Converts self
into an Option<E>
, consuming self
,\nand discarding the success value, if any.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.err(), None);\n\nlet x: Result<u32, &str> = Err(\"Nothing here\");\nassert_eq!(x.err(), Some(\"Nothing here\"));
Converts from &Result<T, E>
to Result<&T, &E>
.
Produces a new Result
, containing a reference\ninto the original, leaving the original in place.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(x.as_ref(), Ok(&2));\n\nlet x: Result<u32, &str> = Err(\"Error\");\nassert_eq!(x.as_ref(), Err(&\"Error\"));
Converts from &mut Result<T, E>
to Result<&mut T, &mut E>
.
fn mutate(r: &mut Result<i32, i32>) {\n match r.as_mut() {\n Ok(v) => *v = 42,\n Err(e) => *e = 0,\n }\n}\n\nlet mut x: Result<i32, i32> = Ok(2);\nmutate(&mut x);\nassert_eq!(x.unwrap(), 42);\n\nlet mut x: Result<i32, i32> = Err(13);\nmutate(&mut x);\nassert_eq!(x.unwrap_err(), 0);
Maps a Result<T, E>
to Result<U, E>
by applying a function to a\ncontained Ok
value, leaving an Err
value untouched.
This function can be used to compose the results of two functions.
\nPrint the numbers on each line of a string multiplied by two.
\n\nlet line = \"1\\n2\\n3\\n4\\n\";\n\nfor num in line.lines() {\n match num.parse::<i32>().map(|i| i * 2) {\n Ok(n) => println!(\"{n}\"),\n Err(..) => {}\n }\n}
Returns the provided default (if Err
), or\napplies a function to the contained value (if Ok
).
Arguments passed to map_or
are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use map_or_else
,\nwhich is lazily evaluated.
let x: Result<_, &str> = Ok(\"foo\");\nassert_eq!(x.map_or(42, |v| v.len()), 3);\n\nlet x: Result<&str, _> = Err(\"bar\");\nassert_eq!(x.map_or(42, |v| v.len()), 42);
Maps a Result<T, E>
to U
by applying fallback function default
to\na contained Err
value, or function f
to a contained Ok
value.
This function can be used to unpack a successful result\nwhile handling an error.
\nlet k = 21;\n\nlet x : Result<_, &str> = Ok(\"foo\");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 3);\n\nlet x : Result<&str, _> = Err(\"bar\");\nassert_eq!(x.map_or_else(|e| k * 2, |v| v.len()), 42);
Maps a Result<T, E>
to Result<T, F>
by applying a function to a\ncontained Err
value, leaving an Ok
value untouched.
This function can be used to pass through a successful result while handling\nan error.
\nfn stringify(x: u32) -> String { format!(\"error code: {x}\") }\n\nlet x: Result<u32, u32> = Ok(2);\nassert_eq!(x.map_err(stringify), Ok(2));\n\nlet x: Result<u32, u32> = Err(13);\nassert_eq!(x.map_err(stringify), Err(\"error code: 13\".to_string()));
Converts from Result<T, E>
(or &Result<T, E>
) to Result<&<T as Deref>::Target, &E>
.
Coerces the Ok
variant of the original Result
via Deref
\nand returns the new Result
.
let x: Result<String, u32> = Ok(\"hello\".to_string());\nlet y: Result<&str, &u32> = Ok(\"hello\");\nassert_eq!(x.as_deref(), y);\n\nlet x: Result<String, u32> = Err(42);\nlet y: Result<&str, &u32> = Err(&42);\nassert_eq!(x.as_deref(), y);
Converts from Result<T, E>
(or &mut Result<T, E>
) to Result<&mut <T as DerefMut>::Target, &mut E>
.
Coerces the Ok
variant of the original Result
via DerefMut
\nand returns the new Result
.
let mut s = \"HELLO\".to_string();\nlet mut x: Result<String, u32> = Ok(\"hello\".to_string());\nlet y: Result<&mut str, &mut u32> = Ok(&mut s);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);\n\nlet mut i = 42;\nlet mut x: Result<String, u32> = Err(42);\nlet y: Result<&mut str, &mut u32> = Err(&mut i);\nassert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
Returns an iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let x: Result<u32, &str> = Ok(7);\nassert_eq!(x.iter().next(), Some(&7));\n\nlet x: Result<u32, &str> = Err(\"nothing!\");\nassert_eq!(x.iter().next(), None);
Returns a mutable iterator over the possibly contained value.
\nThe iterator yields one value if the result is Result::Ok
, otherwise none.
let mut x: Result<u32, &str> = Ok(7);\nmatch x.iter_mut().next() {\n Some(v) => *v = 40,\n None => {},\n}\nassert_eq!(x, Ok(40));\n\nlet mut x: Result<u32, &str> = Err(\"nothing!\");\nassert_eq!(x.iter_mut().next(), None);
Returns the contained Ok
value, consuming the self
value.
Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err
\ncase explicitly, or call unwrap_or
, unwrap_or_else
, or\nunwrap_or_default
.
Panics if the value is an Err
, with a panic message including the\npassed message, and the content of the Err
.
let x: Result<u32, &str> = Err(\"emergency failure\");\nx.expect(\"Testing expect\"); // panics with `Testing expect: emergency failure`
We recommend that expect
messages are used to describe the reason you\nexpect the Result
should be Ok
.
let path = std::env::var(\"IMPORTANT_PATH\")\n .expect(\"env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`\");
Hint: If you’re having trouble remembering how to phrase expect\nerror messages remember to focus on the word “should” as in “env\nvariable should be set by blah” or “the given binary should be available\nand executable by the current user”.
\nFor more detail on expect message styles and the reasoning behind our recommendation please\nrefer to the section on “Common Message\nStyles” in the\nstd::error
module docs.
Returns the contained Ok
value, consuming the self
value.
Because this function may panic, its use is generally discouraged.\nInstead, prefer to use pattern matching and handle the Err
\ncase explicitly, or call unwrap_or
, unwrap_or_else
, or\nunwrap_or_default
.
Panics if the value is an Err
, with a panic message provided by the\nErr
’s value.
Basic usage:
\n\nlet x: Result<u32, &str> = Ok(2);\nassert_eq!(x.unwrap(), 2);
let x: Result<u32, &str> = Err(\"emergency failure\");\nx.unwrap(); // panics with `emergency failure`
Returns the contained Ok
value or a default
Consumes the self
argument then, if Ok
, returns the contained\nvalue, otherwise if Err
, returns the default value for that\ntype.
Converts a string to an integer, turning poorly-formed strings\ninto 0 (the default value for integers). parse
converts\na string to any other type that implements FromStr
, returning an\nErr
on error.
let good_year_from_input = \"1909\";\nlet bad_year_from_input = \"190blarg\";\nlet good_year = good_year_from_input.parse().unwrap_or_default();\nlet bad_year = bad_year_from_input.parse().unwrap_or_default();\n\nassert_eq!(1909, good_year);\nassert_eq!(0, bad_year);
Returns the contained Err
value, consuming the self
value.
Panics if the value is an Ok
, with a panic message including the\npassed message, and the content of the Ok
.
let x: Result<u32, &str> = Ok(10);\nx.expect_err(\"Testing expect_err\"); // panics with `Testing expect_err: 10`
Returns the contained Err
value, consuming the self
value.
Panics if the value is an Ok
, with a custom panic message provided\nby the Ok
’s value.
let x: Result<u32, &str> = Ok(2);\nx.unwrap_err(); // panics with `2`
let x: Result<u32, &str> = Err(\"emergency failure\");\nassert_eq!(x.unwrap_err(), \"emergency failure\");
unwrap_infallible
)Returns the contained Ok
value, but never panics.
Unlike unwrap
, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap
as a maintainability safeguard that will fail\nto compile if the error type of the Result
is later changed\nto an error that can actually occur.
\nfn only_good_news() -> Result<String, !> {\n Ok(\"this is fine\".into())\n}\n\nlet s: String = only_good_news().into_ok();\nprintln!(\"{s}\");
unwrap_infallible
)Returns the contained Err
value, but never panics.
Unlike unwrap_err
, this method is known to never panic on the\nresult types it is implemented for. Therefore, it can be used\ninstead of unwrap_err
as a maintainability safeguard that will fail\nto compile if the ok type of the Result
is later changed\nto a type that can actually occur.
\nfn only_bad_news() -> Result<!, String> {\n Err(\"Oops, it failed\".into())\n}\n\nlet error: String = only_bad_news().into_err();\nprintln!(\"{error}\");
Returns res
if the result is Ok
, otherwise returns the Err
value of self
.
Arguments passed to and
are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use and_then
, which is\nlazily evaluated.
let x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Err(\"late error\");\nassert_eq!(x.and(y), Err(\"late error\"));\n\nlet x: Result<u32, &str> = Err(\"early error\");\nlet y: Result<&str, &str> = Ok(\"foo\");\nassert_eq!(x.and(y), Err(\"early error\"));\n\nlet x: Result<u32, &str> = Err(\"not a 2\");\nlet y: Result<&str, &str> = Err(\"late error\");\nassert_eq!(x.and(y), Err(\"not a 2\"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<&str, &str> = Ok(\"different result type\");\nassert_eq!(x.and(y), Ok(\"different result type\"));
Calls op
if the result is Ok
, otherwise returns the Err
value of self
.
This function can be used for control flow based on Result
values.
fn sq_then_to_string(x: u32) -> Result<String, &'static str> {\n x.checked_mul(x).map(|sq| sq.to_string()).ok_or(\"overflowed\")\n}\n\nassert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));\nassert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err(\"overflowed\"));\nassert_eq!(Err(\"not a number\").and_then(sq_then_to_string), Err(\"not a number\"));
Often used to chain fallible operations that may return Err
.
use std::{io::ErrorKind, path::Path};\n\n// Note: on Windows \"/\" maps to \"C:\\\"\nlet root_modified_time = Path::new(\"/\").metadata().and_then(|md| md.modified());\nassert!(root_modified_time.is_ok());\n\nlet should_fail = Path::new(\"/bad/path\").metadata().and_then(|md| md.modified());\nassert!(should_fail.is_err());\nassert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
Returns res
if the result is Err
, otherwise returns the Ok
value of self
.
Arguments passed to or
are eagerly evaluated; if you are passing the\nresult of a function call, it is recommended to use or_else
, which is\nlazily evaluated.
let x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Err(\"late error\");\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err(\"early error\");\nlet y: Result<u32, &str> = Ok(2);\nassert_eq!(x.or(y), Ok(2));\n\nlet x: Result<u32, &str> = Err(\"not a 2\");\nlet y: Result<u32, &str> = Err(\"late error\");\nassert_eq!(x.or(y), Err(\"late error\"));\n\nlet x: Result<u32, &str> = Ok(2);\nlet y: Result<u32, &str> = Ok(100);\nassert_eq!(x.or(y), Ok(2));
Calls op
if the result is Err
, otherwise returns the Ok
value of self
.
This function can be used for control flow based on result values.
\nfn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }\nfn err(x: u32) -> Result<u32, u32> { Err(x) }\n\nassert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));\nassert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));\nassert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));\nassert_eq!(Err(3).or_else(err).or_else(err), Err(3));
Returns the contained Ok
value or a provided default.
Arguments passed to unwrap_or
are eagerly evaluated; if you are passing\nthe result of a function call, it is recommended to use unwrap_or_else
,\nwhich is lazily evaluated.
let default = 2;\nlet x: Result<u32, &str> = Ok(9);\nassert_eq!(x.unwrap_or(default), 9);\n\nlet x: Result<u32, &str> = Err(\"error\");\nassert_eq!(x.unwrap_or(default), default);
Returns the contained Ok
value, consuming the self
value,\nwithout checking that the value is not an Err
.
Calling this method on an Err
is undefined behavior.
let x: Result<u32, &str> = Ok(2);\nassert_eq!(unsafe { x.unwrap_unchecked() }, 2);
let x: Result<u32, &str> = Err(\"emergency failure\");\nunsafe { x.unwrap_unchecked(); } // Undefined behavior!
Returns the contained Err
value, consuming the self
value,\nwithout checking that the value is not an Ok
.
Calling this method on an Ok
is undefined behavior.
let x: Result<u32, &str> = Ok(2);\nunsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
let x: Result<u32, &str> = Err(\"emergency failure\");\nassert_eq!(unsafe { x.unwrap_err_unchecked() }, \"emergency failure\");
Takes each element in the Iterator
: if it is an Err
, no further\nelements are taken, and the Err
is returned. Should no Err
\noccur, the sum of all elements is returned.
This sums up every integer in a vector, rejecting the sum if a negative\nelement is encountered:
\n\nlet f = |&x: &i32| if x < 0 { Err(\"Negative element found\") } else { Ok(x) };\nlet v = vec![1, 2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Ok(3));\nlet v = vec![1, -2];\nlet res: Result<i32, _> = v.iter().map(f).sum();\nassert_eq!(res, Err(\"Negative element found\"));
try_trait_v2
)?
when not short-circuiting.try_trait_v2
)FromResidual::from_residual
\nas part of ?
when short-circuiting. Read moretry_trait_v2
)Output
type. Read moretry_trait_v2
)?
to decide whether the operator should produce a value\n(because this returned ControlFlow::Continue
)\nor propagate a value back to the caller\n(because this returned ControlFlow::Break
). Read more