Overengineered HTML Codeblocks

The What

#![(allocator_api)]
use std::{
    alloc::{, },
    cell::,
    marker::,
    ptr::,
};

pub struct <: ?, :  = > {
    : <<>>,
    : <<>>,
    : ,
}

struct <: ?> {
    : <>,
    : <>,
    : ,
}

fn () {
  !("This example isn't particularly interesting to run...");
}

By the way, the sample above was created by slapping this on top of my djot codeblock:

{ ="alloc/rc.rs" number="4" highlight="14,19..=20" hide="4..=11,17,23.." tool="playground" tool="godbolt" tool-version="nightly" }

Features

  1. Line numbering with optional starting number
  2. Line highlighting, for multiple disjoint ranges
  3. Line hiding, for multiple disjoint ranges
    • Allow toggling visiblity of the hidden lines
    • Show an indicator that some lines are hidden
  4. Codeblock metadata, for example the file name or the programming language used.
  5. Allow linking to online execution environments that contain the contents of the codeblock
  6. Allow IDE-like hover information for tokens through clicking.

Requirements

  • HTML used should be semantic and accessible.

  • Interactive items should work with keyboard navigation.

  • Generated HTML should look proper in Firefox Reader Mode.

  • To the greatest extent possible, all features should work without Javascript.

The How

Note: I’m going to assume you have control of the markup -> HTML pipeline in some shape or form. Personally, I use djot and a custom filter in my static site generator.

Line Numbering

  1. Wrap each line of code: <span class="line">.
  2. Add a class to the containing codeblock: <code class="number-lines">.
  3. If the starting number is not 1, use a custom property to set the starting number: style="--number-start: 4;" [1].
  1. Why not data attributes? As much as I would like to just have data-line-number=4 instead of a class and a CSS variable, as of today the attr() function only works with the content property.

  1. Create a CSS counter, then use the ::before pseudo-element to add the current line number [2].

      Minimal CSS
    code.number-lines {
      counter-reset: line-number-step;
      counter-increment: line-number-step calc(var(--number-start, 1) - 1);
    
      & .line::before {
        display: inline-block;
        content: counter(line-number-step, decimal-leading-zero);
        counter-increment: line-number-step;
      }
    }
  1. Using the ::before pseudo-element ensures that selecting the codeblock content with a mouse does not also select the line numbers.

Line Highlighting

  1. Add a class to each highlighted line of code: <span class="line line-highlight">.

  2. Change the styling of the line as desired using CSS:

      Minimal CSS
    code .line-highlight {
      background-color: rgb(92 91 94);
      border-color: rgb(12 12 14);
    }

Line Hiding

  1. Add a class to each hidden line of code: <span class="line line-hidden">.

  2. Hide the line while still making it accessible to screen readers and non-CSS environments:

    code .line-hidden {
      position: absolute;
      left: -99999px;
      top: auto;
    }
  3. When creating the code block, if the code block contains hidden lines, add a checkbox before the <code> element:

    <label class="toggle-line-hidden">
      <input type="checkbox">
      <span>Toggle N hidden lines</span>
    </label>
    <code>
      <span>Some code</span>
    </code>
  4. Unhide the hidden lines by resetting its position if the checkbox is checked [3]:

    label.toggle-line-hidden:has(> input:checked) + code {
      & .line {
        --hint-color: transparent;
      }
    
      & .line-hidden {
        position: relative;
        left: auto;
      }
    }
  1. You might have noticed that I am using fairly recent CSS features here; at the time of writing, :has is at 92% usage and CSS nesting is at 87% usage. This is done considering my target audience. Consider restructuring your HTML/CSS or use polyfills depending on your requirements.

  1. Add CSS to show an indicator that lines are hidden:

    /* When lines are numbered */
    code .line-hidden+.line:not(.line-hidden)::before {
      border-top: 2px dotted var(--hint-color);
    }
    
    code .line:not(.line-hidden):has(+ .line-hidden)::before {
      border-bottom: 2px dotted var(--hint-color);
    }
    
    /* When lines are not numbered */
    code:not(.number-lines) .line-hidden+.line:not(.line-hidden)::before {
      display: block;
      content: "";
      width: 4%;
      margin-top: 1px;
    }
    
    code:not(.number-lines) .line:not(.line-hidden):has(+ .line-hidden)::after {
      display: block;
      content: "";
      width: 4%;
      border-bottom: 2px dotted var(--hint-color);
      margin-top: 1px;
    }

    The --hint-color variable is used to disable the indicator when hidden lines are shown (see the 4th step).

Codeblock Metadata

Fairly simple considering the other features, add some sort of <span> or <ul> element before the codeblock and style it using CSS.

Online Execution Environments

  1. Grab the text content of the code block.
  2. Turn it into a link to the execution environment using the appropriate format.
  3. Add the link to the information block like in Codeblock Metadata.

Example: Godbolt

Compiler Explorer allows you to open the website with a certain ClientState loaded:

  1. Encode the ClientState JSON body with url-safe base64.

  2. Optional: Compress the JSON with zlib before encoding.

  3. Append the body to https://godbolt.org/clientstate/.

      Example Rust Code
    use std::io:: as _;
    use base64:: as _;
    
    fn (
        : &mut <(&, )>,
        : &,
        : &,
        : &,
    ) ->  {
        if  != "godbolt" {
            return false;
        }
    
        let  = match  {
            "c" => {
                serde_json::!({
                    "sessions": [{
                        "id": 1, "language": "c", "source": &,
                        "compilers": [{
                            "id": "cclang_trunk", "filters": { "binary": true, "execute": true },
                            "options": "-O0 -g -fsanitize=leak"
                        }],
                    }],
                })
            }
            "rust" => {
                serde_json::!({
                    "sessions": [{
                        "id": 1, "language": "rust", "source": &,
                        "compilers": [{
                            "id": "nightly", "filters": { "binary": true, "execute": true },
                        }],
                    }],
                })
            }
            _ => return false,
        };
    
        let mut  = ::("https://godbolt.org/clientstate/");
        let mut  = flate2::write::::(::(), flate2::::());
        .(.().()).();
        let  = .().();
        base64::prelude::.(, &mut );
        .(("godbolt", ));
        true
    }

IDE Hover Information

I currently only have this feature for Rust due to relative ease of implementation. It’s also not perfect! Here’s how I do it:

Preprocessing

  1. As a separate build step, crawl all Rust code blocks, and for each code block place the source code into a temporary directory, then run rust-analyzer lsif to generate Language Server Index Format data.
  2. Deserialize the resulting JSON and grab the Ranges associated with all Hover results.
  3. Store the range -> hover mappings on disk. The mappings have to be associated with their source code blocks (I use a hash).

Rendering

  1. Read the mappings from disk.
  2. When syntax highlighting Rust source code, check if each token produced is contained within any range registered with a hover.
  3. If so, wrap the token in a <label> with an <input type="button"> [4]. I use HTML popover elements for the “hover” information, so hash the hover content and save it for later, emitting the hash in the <input> [5]:
    <label class="type.builtin lsp-hover-ref">
      usize
      <input type="button" popovertarget="11498124591756402886">
    </label>
  1. Popover elements can be invoked by <button> or <input type="button"> elements. Initially, I went with <button> as it seemed like no-brainer for semantics, but Firefox Reader Mode does not display any button content (with no workarounds AFAIK).

  2. This allows multiple labels to share the same hover content (eg. documentation for the same type used multiple times throughout the article), greatly reducing the HTML output size.

  1. After rendering the page contents, render the popovers [6]:
    <div id="11498124591756402886" popover class="lsp-hover">
      <label>
        <input class="fullscreen" type="checkbox">
        <span>Toggle fullscreen</span>
      </label>
      <div class="lsp-hover-content">
       <pre class="highlighted"><code class="lang-rust"><span class="line"><span class="type.builtin">usize</span></span></code></pre>
       <hr>
       <p>The pointer-sized unsigned integer type.</p>
       <p>The size of this primitive is how many bytes it takes to reference any location in memory. For example, on a 32 bit target, this is 4 bytes and on a 64 bit target, this is 8 bytes.</p>
      </div>
    </div>
  1. Since rust-analyzer produces hover information in Markdown, my site generator renders them as such so bold/italic text render properly, code blocks have syntax highlighting, etc…

Styling

  1. Popover elements are centered by default and positioning options are limited. Until anchor positioning arrives so I can place the hover information near clicked tokens, I position popups in the bottom right corner:

    .lsp-hover {
      inset: unset;
      position: fixed;
      bottom: var(--space-s);
      right: var(--space-s);
      max-width: calc(min(48ch, 95vw) - var(--space-s));
      max-height: 40vh;
    
      background-color: var(--theme-background-alt);
      border: 2px solid var(--theme-foreground-alt);
    
      font-size: var(--step--1);
    }
  2. Using the same checkbox method as Line Hiding, the hover content can be expanded:

    .lsp-hover:has(.fullscreen:checked) {
      min-width: calc(100vw - var(--space-s) * 2);
      min-height: calc(100vh - var(--space-s) * 2);
    }
  3. On smaller viewports, code blocks situated at the end of an article can be covered by the popup, so increase the bottom margin to allow scroll-positioning the code block above the popup:

    article:has(> .lsp-hover:popover-open) {
      margin-bottom: calc(40vh + var(--space-s) * 2);
    }
  4. The <input> elements can be keyboard-focused, but since they do not contain any content we have to style the parent <label> instead.

    .lsp-hover-ref {
      user-select: text;
      cursor: pointer;
    
      &:focus-within {
        position: relative;
        z-index: 1;
        outline: var(--theme-focus) solid 2px;
      }
    
      & > input:focus-visible {
        outline-color: transparent;
      }
    }
  5. Since <input> elements can be keyboard-focused, if they are hidden there is no indication to the user. So, the following addendum to the CSS unhides hidden lines if any tokens are keyboard-focused:

    label.toggle-line-hidden:has(> input:checked) + code,
    code:has(:focus-visible) {
      & .line {
        --hint-color: transparent;
      }
    
      & .line-hidden {
        position: relative;
        left: auto;
      }
    }
  6. In Firefox (not Chrome), the use of <input> causes copying and pasting the code block content (with Ctrl-c and Ctrl-v) to insert redundant, aggravating newlines, completely ruining the pasted content:

      Example broken output
    pub struct Rc
    
    <T
    
    : ?Sized
    
    , A
    
    : Allocator
    
     = Global
    
    > {
    

    This can be worked around like so: For code blocks that contain hover information, the parent <pre> tag is made focusable using tabindex="0", then the following CSS removes the <input> elements from the layout flow if the code block is mouse-focused but not keyboard-focused:

    pre:focus:not(:focus-visible) .lsp-hover-ref > input {
      display: none;
    }

Conclusion

Love it? Hate it? Let me know!

Behold, a story in three posts on the orange site:

Sourcegraph
nom::character::complete
pub fn digit0<T, E>(input: T) -> IResult<T, T, E>
where
    E: ParseError<T>,
    T: InputTakeAtPosition,
    <T as InputTakeAtPosition>::Item: AsChar,

Recognizes zero or more ASCII numerical characters: 0-9

Complete version: Will return an error if there’s not enough input data, or the whole input if no terminating token is found (a non digit character).

Example

fn parser(input: &str) -> IResult<&str, &str> {
    digit0(input)
}

assert_eq!(parser("21c"), Ok(("c", "21")));
assert_eq!(parser("21"), Ok(("", "21")));
assert_eq!(parser("a21c"), Ok(("a21c", "")));
assert_eq!(parser(""), Ok(("", "")));
src
struct RcBox<T>
where
    T: ?Sized,
{
    strong: Cell<usize>,
    weak: Cell<usize>,
    value: T,
}
core::option::Option
Some(T)

Some value of type T.

src
fn main()
src::RangeSet
pub fn contains(&self, idx: usize) -> bool
idx: usize
usize

The pointer-sized unsigned integer type.

The size of this primitive is how many bytes it takes to reference any location in memory. For example, on a 32 bit target, this is 4 bytes and on a 64 bit target, this is 8 bytes.

range_set_blaze::RangeSetBlaze
impl<T> RangeSetBlaze<T>
pub fn ranges_insert(&mut self, range: RangeInclusive<T>) -> bool
where
    // Bounds from impl:
    T: Integer,

Adds a range to the set.

Returns whether any values where newly inserted. That is:

  • If the set did not previously contain some value in the range, true is returned.
  • If the set already contained every value in the range, false is returned, and the entry is not updated.

Performance

Inserting n items will take in O(n log m) time, where n is the number of inserted items and m is the number of ranges in self. When n is large, consider using | which is O(n+m) time.

Examples

use range_set_blaze::RangeSetBlaze;

let mut set = RangeSetBlaze::new();

assert_eq!(set.ranges_insert(2..=5), true);
assert_eq!(set.ranges_insert(5..=6), true);
assert_eq!(set.ranges_insert(3..=4), false);
assert_eq!(set.len(), 5usize);
let mut url: String
src::Rc
alloc: A
base64::engine
// Dyn Compatible: No
// - Reason: has a method `encode` that is non dispatchable because of:
//   - a non-lifetime generic parameter
pub trait Engine
where
    Self: Send + Sync,

An Engine provides low-level encoding and decoding operations that all other higher-level parts of the API use. Users of the library will generally not need to implement this.

Different implementations offer different characteristics. The library currently ships with GeneralPurpose that offers good speed and works on any CPU, with more choices coming later, like a constant-time one when side channel resistance is called for, and vendor-specific vectorized ones for more speed.

See general_purpose::STANDARD_NO_PAD if you just want standard base64. Otherwise, when possible, it’s recommended to store the engine in a const so that references to it won’t pose any lifetime issues, and to avoid repeating the cost of engine setup.

Since almost nobody will need to implement Engine, docs for internal methods are hidden.

src::RangeSet
0: RangeSetBlaze<usize>
range_set_blaze::RangeSetBlaze
impl<T> RangeSetBlaze<T>
pub fn contains(&self, value: T) -> bool
where
    // Bounds from impl:
    T: Integer,

Returns true if the set contains an element equal to the value.

Examples

use range_set_blaze::RangeSetBlaze;

let set = RangeSetBlaze::from_iter([1, 2, 3]);
assert_eq!(set.contains(1), true);
assert_eq!(set.contains(4), false);
core::default
macro Default

Derive macro generating an impl of the trait Default.

'static
nom::internal
// Dyn Compatible: Yes
pub trait Parser<I, O, E>

All nom parsers implement this trait

bool

The boolean type.

The bool represents a value, which could only be either true or false. If you cast a bool into an integer, true will be 1 and false will be 0.

Basic usage

bool implements various traits, such as [BitAnd], [BitOr], [Not], etc., which allow us to perform boolean operations using &, | and !.

if requires a bool value as its conditional. assert!, which is an important macro in testing, checks whether an expression is true and panics if it isn’t.

let bool_val = true & false | false;
assert!(!bool_val);

Examples

A trivial example of the usage of bool:

let praise_the_borrow_checker = true;

// using the `if` conditional
if praise_the_borrow_checker {
    println!("oh, yeah!");
} else {
    println!("what?!!");
}

// ... or, a match pattern
match praise_the_borrow_checker {
    true => println!("keep praising!"),
    false => println!("you should praise!"),
}

Also, since bool implements the Copy trait, we don’t have to worry about the move semantics (just like the integer and float primitives).

Now an example of bool cast to integer type:

assert_eq!(true as i32, 1);
assert_eq!(false as i32, 0);
core::ptr::non_null
pub struct NonNull<T>
where
    T: ?Sized,
{
    pointer: *const T,
}

*mut T but non-zero and covariant.

This is often the correct thing to use when building data structures using raw pointers, but is ultimately more dangerous to use because of its additional properties. If you’re not sure if you should use NonNull<T>, just use *mut T!

Unlike *mut T, the pointer must always be non-null, even if the pointer is never dereferenced. This is so that enums may use this forbidden value as a discriminant – Option<NonNull<T>> has the same size as *mut T. However the pointer may still dangle if it isn’t dereferenced.

Unlike *mut T, NonNull<T> was chosen to be covariant over T. This makes it possible to use NonNull<T> when building covariant types, but introduces the risk of unsoundness if used in a type that shouldn’t actually be covariant. (The opposite choice was made for *mut T even though technically the unsoundness could only be caused by calling unsafe functions.)

Covariance is correct for most safe abstractions, such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they provide a public API that follows the normal shared XOR mutable rules of Rust.

If your type cannot safely be covariant, you must ensure it contains some additional field to provide invariance. Often this field will be a [PhantomData] type like PhantomData<Cell<T>> or PhantomData<&'a mut T>.

Notice that NonNull<T> has a From instance for &T. However, this does not change the fact that mutating through a (pointer derived from a) shared reference is undefined behavior unless the mutation happens inside an [UnsafeCell<T>]. The same goes for creating a mutable reference from a shared reference. When using this From instance without an UnsafeCell<T>, it is your responsibility to ensure that as_mut is never called, and as_ptr is never used for mutation.

Representation

Thanks to the [null pointer optimization], NonNull<T> and Option<NonNull<T>> are guaranteed to have the same size and alignment:

use std::ptr::NonNull;

assert_eq!(size_of::<NonNull<i16>>(), size_of::<Option<NonNull<i16>>>());
assert_eq!(align_of::<NonNull<i16>>(), align_of::<Option<NonNull<i16>>>());

assert_eq!(size_of::<NonNull<str>>(), size_of::<Option<NonNull<str>>>());
assert_eq!(align_of::<NonNull<str>>(), align_of::<Option<NonNull<str>>>());
nom::character::complete
pub fn digit1<T, E>(input: T) -> IResult<T, T, E>
where
    E: ParseError<T>,
    T: InputTakeAtPosition,
    <T as InputTakeAtPosition>::Item: AsChar,

Recognizes one or more ASCII numerical characters: 0-9

Complete version: Will return an error if there’s not enough input data, or the whole input if no terminating token is found (a non digit character).

Example

fn parser(input: &str) -> IResult<&str, &str> {
    digit1(input)
}

assert_eq!(parser("21c"), Ok(("c", "21")));
assert_eq!(parser("c1"), Err(Err::Error(Error::new("c1", ErrorKind::Digit))));
assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Digit))));

Parsing an integer

You can use digit1 in combination with [map_res] to parse an integer:

fn parser(input: &str) -> IResult<&str, u32> {
  map_res(digit1, str::parse)(input)
}

assert_eq!(parser("416"), Ok(("", 416)));
assert_eq!(parser("12b"), Ok(("b", 12)));
assert!(parser("b").is_err());
alloc::alloc
pub struct Global

The global memory allocator.

This type implements the Allocator trait by forwarding calls to the allocator registered with the #[global_allocator] attribute if there is one, or the std crate’s default.

Note: while this type is unstable, the functionality it provides can be accessed through the free functions in alloc.

alloc::vec::Vec
impl<T, A> Vec<T, A>
pub fn push(&mut self, value: T)
where
    // Bounds from impl:
    A: Allocator,

Appends an element to the back of a collection.

Panics

Panics if the new capacity exceeds isize::MAX bytes.

Examples

let mut vec = vec![1, 2];
vec.push(3);
assert_eq!(vec, [1, 2, 3]);

Time complexity

Takes amortized O(1) time. If the vector’s length would exceed its capacity after the push, O(capacity) time is taken to copy the vector’s elements to a larger allocation. This expensive operation is offset by the capacity O(1) insertions it allows.

tool: &str
std::io
// Dyn Compatible: Yes
pub trait Write

A trait for objects which are byte-oriented sinks.

Implementors of the Write trait are sometimes called ‘writers’.

Writers are defined by two required methods, [write] and [flush]:

  • The [write] method will attempt to write some data into the object, returning how many bytes were successfully written.

  • The [flush] method is useful for adapters and explicit buffers themselves for ensuring that all buffered data has been pushed out to the ‘true sink’.

Writers are intended to be composable with one another. Many implementors throughout [std::io] take and provide types which implement the Write trait.

Examples

use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let data = b"some bytes";

    let mut pos = 0;
    let mut buffer = File::create("foo.txt")?;

    while pos < data.len() {
        let bytes_written = buffer.write(&data[pos..])?;
        pos += bytes_written;
    }
    Ok(())
}

The trait also provides convenience methods like [write_all], which calls write in a loop until its entire input has been written.

// Implements notable traits: Write
let args: Vec<u8>
core::result
pub enum Result<T, E> {
    Ok( /* … */ ),
    Err( /* … */ ),
}

Result is a type that represents either success (Ok) or failure (Err).

See the documentation for details.

nom::branch
pub fn alt<I, O, E, List>(mut l: List) -> impl FnMut(I) -> IResult<I, O, E>
where
    I: Clone,
    E: ParseError<I>,
    List: Alt<I, O, E>,

Tests a list of parsers one by one until one succeeds.

It takes as argument a tuple of parsers. There is a maximum of 21 parsers. If you need more, it is possible to nest them in other alt calls, like this: alt(parser_a, alt(parser_b, parser_c))

use nom::character::complete::{alpha1, digit1};
use nom::branch::alt;
fn parser(input: &str) -> IResult<&str, &str> {
  alt((alpha1, digit1))(input)
};

// the first parser, alpha1, recognizes the input
assert_eq!(parser("abc"), Ok(("", "abc")));

// the first parser returns an error, so alt tries the second one
assert_eq!(parser("123456"), Ok(("", "123456")));

// both parsers failed, and with the default error type, alt will return the last error
assert_eq!(parser(" "), Err(Err::Error(error_position!(" ", ErrorKind::Digit))));

With a custom error type, it is possible to have alt return the error of the parser that went the farthest in the input data

core::alloc
// Dyn Compatible: Yes
pub unsafe trait Allocator

An implementation of Allocator can allocate, grow, shrink, and deallocate arbitrary blocks of data described via Layout.

Allocator is designed to be implemented on ZSTs, references, or smart pointers because having an allocator like MyAlloc([u8; N]) cannot be moved, without updating the pointers to the allocated memory.

Unlike GlobalAlloc, zero-sized allocations are allowed in Allocator. If an underlying allocator does not support this (like jemalloc) or return a null pointer (such as libc::malloc), this must be caught by the implementation.

Currently allocated memory

Some of the methods require that a memory block be currently allocated via an allocator. This means that:

  • the starting address for that memory block was previously returned by [allocate], [grow], or [shrink], and

  • the memory block has not been subsequently deallocated, where blocks are either deallocated directly by being passed to [deallocate] or were changed by being passed to [grow] or [shrink] that returns Ok. If grow or shrink have returned Err, the passed pointer remains valid.

Memory fitting

Some of the methods require that a layout fit a memory block. What it means for a layout to “fit” a memory block means (or equivalently, for a memory block to “fit” a layout) is that the following conditions must hold:

  • The block must be allocated with the same alignment as [layout.align], and

  • The provided [layout.size] must fall in the range min ..= max, where:

    • min is the size of the layout most recently used to allocate the block, and
    • max is the latest actual size returned from [allocate], [grow], or [shrink].

Safety

  • Memory blocks returned from an allocator that are currently allocated must point to valid memory and retain their validity while they are currently allocated and the shorter of:

    • the borrow-checker lifetime of the allocator type itself.
    • as long as at least one of the instance and all of its clones has not been dropped.
  • copying, cloning, or moving the allocator must not invalidate memory blocks returned from this allocator. A copied or cloned allocator must behave like the same allocator, and

  • any pointer to a memory block which is currently allocated may be passed to any other method of the allocator.

alloc::string::String
pub fn as_bytes(&self) -> &[u8]

Returns a byte slice of this String’s contents.

The inverse of this method is [from_utf8].

Examples

let s = String::from("hello");

assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
core::result::Result
impl<T, E> Result<T, E>
pub fn map<U, F>(self, op: F) -> Result<U, E>
where
    F: FnOnce(T) -> U,

Maps a Result<T, E> to Result<U, E> by applying a function to a contained Ok value, leaving an Err value untouched.

This function can be used to compose the results of two functions.

Examples

Print the numbers on each line of a string multiplied by two.

let line = "1\n2\n3\n4\n";

for num in line.lines() {
    match num.parse::<i32>().map(|i| i * 2) {
        Ok(n) => println!("{n}"),
        Err(..) => {}
    }
}
core::ops::range
pub struct RangeInclusive<Idx> {
    pub(crate) start: Idx,
    pub(crate) end: Idx,
    pub(crate) exhausted: bool,
}

A range bounded inclusively below and above (start..=end).

The RangeInclusive start..=end contains all values with x >= start and x <= end. It is empty unless start <= end.

This iterator is [fused], but the specific values of start and end after iteration has finished are unspecified other than that [.is_empty] will return true once no more values will be produced.

Examples

The start..=end syntax is a RangeInclusive:

assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5));
assert_eq!(3 + 4 + 5, (3..=5).sum());
let arr = [0, 1, 2, 3, 4];
assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
assert_eq!(arr[ .. 3], [0, 1, 2      ]);
assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
assert_eq!(arr[1.. 3], [   1, 2      ]);
assert_eq!(arr[1..=3], [   1, 2, 3   ]); // This is a `RangeInclusive`
nom::internal
pub type IResult<I, O, E = error::Error<I>> = Result<(I, O), Err<E>>

Holds the result of parsing functions

It depends on the input type I, the output type O, and the error type E (by default (I, nom::ErrorKind))

The Ok side is a pair containing the remainder of the input (the part of the data that was not parsed) and the produced value. The Err side contains an instance of nom::Err.

Outside of the parsing code, you can use the Finish::finish method to convert it to a more common result type

alloc::string
impl<T> ToString for T
default fn to_string(&self) -> String
where
    // Bounds from impl:
    T: fmt::Display + ?Sized,

Converts the given value to a String.

Examples

let i = 5;
let five = String::from("5");

assert_eq!(five, i.to_string());
core::str
pub const fn is_empty(&self) -> bool

Returns true if self has a length of zero bytes.

Examples

let s = "";
assert!(s.is_empty());

let s = "not empty";
assert!(!s.is_empty());
A: Allocator
src
fn generate_godbolt_link(links: &mut Vec<(&str, String)>, tool: &str, code: &str, lang: &str) -> bool
// Implements notable traits: Write
let mut encoder: ZlibEncoder<Vec<u8>>
base64::engine::general_purpose
pub const URL_SAFE_NO_PAD: GeneralPurpose = GeneralPurpose { encode_table: [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, 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, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 95], decode_table: [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, 255, 0, 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, 255, 255, 255, 255, 63, 255, 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, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], config: GeneralPurposeConfig { encode_padding: false, decode_allow_trailing_bits: false, decode_padding_mode: RequireNone } }

A GeneralPurpose engine using the alphabet::URL_SAFE base64 alphabet and NO_PAD config.

core::fmt::macros
macro Debug

Derive macro generating an impl of the trait Debug.

src::RcBox
weak: Cell<usize>
core::str
pub fn split<P>(&self, pat: P) -> Split<'_, P>
where
    P: Pattern,

Returns an iterator over substrings of this string slice, separated by characters matched by a pattern.

The [pattern] can be a &str, [char], a slice of [char]s, or a function or closure that determines if a character matches.

Iterator behavior

The returned iterator will be a DoubleEndedIterator if the pattern allows a reverse search and forward/reverse search yields the same elements. This is true for, e.g., [char], but not for &str.

If the pattern allows a reverse search but its results might differ from a forward search, the [rsplit] method can be used.

Examples

Simple patterns:

let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);

let v: Vec<&str> = "".split('X').collect();
assert_eq!(v, [""]);

let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
assert_eq!(v, ["lion", "", "tiger", "leopard"]);

let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
assert_eq!(v, ["lion", "tiger", "leopard"]);

let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
assert_eq!(v, ["abc", "def", "ghi"]);

let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
assert_eq!(v, ["lion", "tiger", "leopard"]);

If the pattern is a slice of chars, split on each occurrence of any of the characters:

let v: Vec<&str> = "2020-11-03 23:59".split(&['-', ' ', ':', '@'][..]).collect();
assert_eq!(v, ["2020", "11", "03", "23", "59"]);

A more complex pattern, using a closure:

let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
assert_eq!(v, ["abc", "def", "ghi"]);

If a string contains multiple contiguous separators, you will end up with empty strings in the output:

let x = "||||a||b|c".to_string();
let d: Vec<_> = x.split('|').collect();

assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);

Contiguous separators are separated by the empty string.

let x = "(///)".to_string();
let d: Vec<_> = x.split('/').collect();

assert_eq!(d, &["(", "", "", ")"]);

Separators at the start or end of a string are neighbored by empty strings.

let d: Vec<_> = "010".split("0").collect();
assert_eq!(d, &["", "1", ""]);

When the empty string is used as a separator, it separates every character in the string, along with the beginning and end of the string.

let f: Vec<_> = "rust".split("").collect();
assert_eq!(f, &["", "r", "u", "s", "t", ""]);

Contiguous separators can lead to possibly surprising behavior when whitespace is used as the separator. This code is correct:

let x = "    a  b c".to_string();
let d: Vec<_> = x.split(' ').collect();

assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);

It does not give you:

assert_eq!(d, &["a", "b", "c"]);

Use [split_whitespace] for this behavior.

src
pub struct RangeSet(RangeSetBlaze<usize>)
nom::sequence
pub fn tuple<I, O, E, List>(mut l: List) -> impl FnMut(I) -> IResult<I, O, E>
where
    E: ParseError<I>,
    List: Tuple<I, O, E>,

Applies a tuple of parsers one by one and returns their results as a tuple. There is a maximum of 21 parsers

use nom::sequence::tuple;
use nom::character::complete::{alpha1, digit1};
let mut parser = tuple((alpha1, digit1, alpha1));

assert_eq!(parser("abc123def"), Ok(("", ("abc", "123", "def"))));
assert_eq!(parser("123def"), Err(Err::Error(("123def", ErrorKind::Alpha))));
src
fn digits(input: &str) -> nom::IResult<&str, Option<usize>>
nom::bytes::complete
pub fn tag<T, Input, Error>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error>
where
    Error: ParseError<Input>,
    Input: InputTake + Compare<T>,
    T: InputLength + Clone,

Recognizes a pattern

The input data will be compared to the tag combinator’s argument and will return the part of the input that matches the argument

It will return Err(Err::Error((_, ErrorKind::Tag))) if the input doesn’t match the pattern

Example

use nom::bytes::complete::tag;

fn parser(s: &str) -> IResult<&str, &str> {
  tag("Hello")(s)
}

assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello")));
assert_eq!(parser("Something"), Err(Err::Error(Error::new("Something", ErrorKind::Tag))));
assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag))));
nom::internal
impl<'a, I, O, E, F> Parser for F
fn parse(&mut self, i: I) -> IResult<I, O, E>
where
    // Bounds from impl:
    F: FnMut(I) -> IResult<I, O, E> + 'a,

A parser takes in input type, and returns a Result containing either the remaining input and the output value, or an error

alloc::string::String
fn from(s: &str) -> String

Converts a &str into a String.

The result is allocated on the heap.

core::result::Result
Ok(T)

Contains the success value

core::cmp
macro PartialEq

Derive macro generating an impl of the trait PartialEq. The behavior of this macro is described in detail here.

flate2
pub struct Compression(u32)

When compressing data, the compression level can be specified by a value in this struct.

core::option::Option
None

No value.

links: &mut Vec<(&str, String)>
core::marker
pub struct PhantomData<T>
where
    T: ?Sized,

Zero-sized type used to mark things that “act like” they own a T.

Adding a PhantomData<T> field to your type tells the compiler that your type acts as though it stores a value of type T, even though it doesn’t really. This information is used when computing certain safety properties.

For a more in-depth explanation of how to use PhantomData<T>, please see the Nomicon.

A ghastly note 👻👻👻

Though they both have scary names, PhantomData and ‘phantom types’ are related, but not identical. A phantom type parameter is simply a type parameter which is never used. In Rust, this often causes the compiler to complain, and the solution is to add a “dummy” use by way of PhantomData.

Examples

Unused lifetime parameters

Perhaps the most common use case for PhantomData is a struct that has an unused lifetime parameter, typically as part of some unsafe code. For example, here is a struct Slice that has two pointers of type *const T, presumably pointing into an array somewhere:

struct Slice<'a, T> {
    start: *const T,
    end: *const T,
}

The intention is that the underlying data is only valid for the lifetime 'a, so Slice should not outlive 'a. However, this intent is not expressed in the code, since there are no uses of the lifetime 'a and hence it is not clear what data it applies to. We can correct this by telling the compiler to act as if the Slice struct contained a reference &'a T:

use std::marker::PhantomData;

struct Slice<'a, T> {
    start: *const T,
    end: *const T,
    phantom: PhantomData<&'a T>,
}

This also in turn infers the lifetime bound T: 'a, indicating that any references in T are valid over the lifetime 'a.

When initializing a Slice you simply provide the value PhantomData for the field phantom:

fn borrow_vec<T>(vec: &Vec<T>) -> Slice<'_, T> {
    let ptr = vec.as_ptr();
    Slice {
        start: ptr,
        end: unsafe { ptr.add(vec.len()) },
        phantom: PhantomData,
    }
}

Unused type parameters

It sometimes happens that you have unused type parameters which indicate what type of data a struct is “tied” to, even though that data is not actually found in the struct itself. Here is an example where this arises with FFI. The foreign interface uses handles of type *mut () to refer to Rust values of different types. We track the Rust type using a phantom type parameter on the struct ExternalResource which wraps a handle.

use std::marker::PhantomData;
use std::mem;

struct ExternalResource<R> {
   resource_handle: *mut (),
   resource_type: PhantomData<R>,
}

impl<R: ResType> ExternalResource<R> {
    fn new() -> Self {
        let size_of_res = mem::size_of::<R>();
        Self {
            resource_handle: foreign_lib::new(size_of_res),
            resource_type: PhantomData,
        }
    }

    fn do_stuff(&self, param: ParamType) {
        let foreign_params = convert_params(param);
        foreign_lib::do_stuff(self.resource_handle, foreign_params);
    }
}

Ownership and the drop check

The exact interaction of PhantomData with drop check may change in the future.

Currently, adding a field of type PhantomData<T> indicates that your type owns data of type T in very rare circumstances. This in turn has effects on the Rust compiler’s [drop check] analysis. For the exact rules, see the [drop check] documentation.

Layout

For all T, the following are guaranteed:

  • size_of::<PhantomData<T>>() == 0
  • align_of::<PhantomData<T>>() == 1
src
pub fn from_range_str(s: &str) -> Result<RangeSet, &'static str>
std::macros
macro_rules! println

Prints to the standard output, with a newline.

On all platforms, the newline is the LINE FEED character (\n/U+000A) alone (no additional CARRIAGE RETURN (\r/U+000D)).

This macro uses the same syntax as format, but writes to the standard output instead. See [std::fmt] for more information.

The println! macro will lock the standard output on each call. If you call println! within a hot loop, this behavior may be the bottleneck of the loop. To avoid this, lock stdout with io::stdout().lock:

use std::io::{stdout, Write};

let mut lock = stdout().lock();
writeln!(lock, "hello world").unwrap();

Use println! only for the primary output of your program. Use [eprintln] instead to print error and progress messages.

See the formatting documentation in std::fmt for details of the macro argument syntax.

Panics

Panics if writing to [io::stdout] fails.

Writing to non-blocking stdout can cause an error, which will lead this macro to panic.

Examples

println!(); // prints just a newline
println!("hello there!");
println!("format {} arguments", "some");
let local_variable = "some";
println!("format {local_variable} arguments");
src::RcBox
strong: Cell<usize>
T: ?Sized
core::cmp
macro Eq

Derive macro generating an impl of the trait Eq.

code: &str
let s: &str
let range: Result<RangeInclusive<usize>, &str>
core::result::Result
impl<T, E> Result<T, E>
pub fn unwrap(self) -> T
where
    E: fmt::Debug,

Returns the contained Ok value, consuming the self value.

Because this function may panic, its use is generally discouraged. Instead, prefer to use pattern matching and handle the Err case explicitly, or call [unwrap_or], [unwrap_or_else], or [unwrap_or_default].

Panics

Panics if the value is an Err, with a panic message provided by the Err’s value.

Examples

Basic usage:

let x: Result<u32, &str> = Ok(2);
assert_eq!(x.unwrap(), 2);
let x: Result<u32, &str> = Err("emergency failure");
x.unwrap(); // panics with `emergency failure`
core::num
pub const fn saturating_sub(self, rhs: Self) -> Self

Saturating integer subtraction. Computes self - rhs, saturating at the numeric bounds instead of overflowing.

Examples

Basic usage:

src
fn get_range(s: &str) -> Result<RangeInclusive<usize>, &'static str>
#[feature]

Valid forms are:

  • #[feature(name1, name2, …)]
core::num
pub const MAX: Self = 18446744073709551615 (0xFFFFFFFFFFFFFFFF)

The largest value that can be represented by this integer type

Examples

Basic usage:

core::cell
pub struct Cell<T>
where
    T: ?Sized,
{
    value: UnsafeCell<T>,
}

A mutable memory location.

Memory layout

Cell<T> has the same memory layout and caveats as UnsafeCell<T>. In particular, this means that Cell<T> has the same in-memory representation as its inner type T.

Examples

In this example, you can see that Cell<T> enables mutation inside an immutable struct. In other words, it enables “interior mutability”.

use std::cell::Cell;

struct SomeStruct {
    regular_field: u8,
    special_field: Cell<u8>,
}

let my_struct = SomeStruct {
    regular_field: 0,
    special_field: Cell::new(1),
};

let new_value = 100;

// ERROR: `my_struct` is immutable
// my_struct.regular_field = new_value;

// WORKS: although `my_struct` is immutable, `special_field` is a `Cell`,
// which can always be mutated
my_struct.special_field.set(new_value);
assert_eq!(my_struct.special_field.get(), new_value);

See the module-level documentation for more.

let num: usize
// Implements notable traits: Iterator<Item = usize>
let range: RangeInclusive<usize>
serde_json::macros
macro_rules! json

Construct a serde_json::Value from a JSON literal.

let value = json!({
    "code": 200,
    "success": true,
    "payload": {
        "features": [
            "serde",
            "json"
        ],
        "homepage": null
    }
});

Variables or expressions can be interpolated into the JSON literal. Any type interpolated into an array element or object value must implement Serde’s Serialize trait, while any type interpolated into a object key must implement Into<String>. If the Serialize implementation of the interpolated type decides to fail, or if the interpolated type contains a map with non-string keys, the json! macro will panic.

let code = 200;
let features = vec!["serde", "json"];

let value = json!({
    "code": code,
    "success": code == 200,
    "payload": {
        features[0]: features[1]
    }
});

Trailing commas are allowed inside both arrays and objects.

let value = json!([
    "notice",
    "the",
    "trailing",
    "comma -->",
]);
range_set_blaze
pub struct RangeSetBlaze<T>
where
    T: Integer,
{
    len: <T as Integer>::SafeLen,
    btree_map: BTreeMap<T, T>,
}

A set of integers stored as sorted & disjoint ranges.

Internally, it stores the ranges in a cache-efficient [BTreeMap].

Table of Contents

RangeSetBlaze Constructors

You can also create RangeSetBlaze’s from unsorted and overlapping integers (or ranges). However, if you know that your input is sorted and disjoint, you can speed up construction.

Here are the constructors, followed by a description of the performance, and then some examples.

Methods Input Notes
[new]/[default]
from_iter/collect integer iterator
from_iter/collect ranges iterator
from_slice slice of integers Fast, but nightly-only
from_sorted_disjoint/into_range_set_blaze SortedDisjoint iterator
from_sorted_starts SortedStarts iterator
from /into array of integers

Constructor Performance

The from_iter/collect constructors are designed to work fast on ‘clumpy’ data. By ‘clumpy’, we mean that the number of ranges needed to represent the data is small compared to the number of input integers. To understand this, consider the internals of the constructors:

Internally, the from_iter/collect constructors take these steps:

  • collect adjacent integers/ranges into disjoint ranges, O(n₁)
  • sort the disjoint ranges by their start, O(n₂ log n₂)
  • merge adjacent ranges, O(n₂)
  • create a BTreeMap from the now sorted & disjoint ranges, O(n₃ log n₃)

where n₁ is the number of input integers/ranges, n₂ is the number of disjoint & unsorted ranges, and n₃ is the final number of sorted & disjoint ranges.

For example, an input of

  • 3, 2, 1, 4, 5, 6, 7, 0, 8, 8, 8, 100, 1, becomes
  • 0..=8, 100..=100, 1..=1, and then
  • 0..=8, 1..=1, 100..=100, and finally
  • 0..=8, 100..=100.

What is the effect of clumpy data? Notice that if n₂ ≈ sqrt(n₁), then construction is O(n₁). (Indeed, as long as n₂n₁/ln(n₁), then construction is O(n₁).) Moreover, we’ll see that set operations are O(n₃). Thus, if n₃ ≈ sqrt(n₁) then set operations are O(sqrt(n₁)), a quadratic improvement an O(n₁) implementation that ignores the clumps.

The from_slice constructor typically provides a constant-time speed up for array-like collections of clumpy integers. On a representative benchmark, the speed up was 7×. The method works by scanning the input for blocks of consecutive integers, and then using from_iter on the results. Where available, it uses SIMD instructions. It is nightly only and enabled by the from_slice feature.

Constructor Examples

use range_set_blaze::prelude::*;

// Create an empty set with 'new' or 'default'.
let a0 = RangeSetBlaze::<i32>::new();
let a1 = RangeSetBlaze::<i32>::default();
assert!(a0 == a1 && a0.is_empty());

// 'from_iter'/'collect': From an iterator of integers.
// Duplicates and out-of-order elements are fine.
let a0 = RangeSetBlaze::from_iter([3, 2, 1, 100, 1]);
let a1: RangeSetBlaze<i32> = [3, 2, 1, 100, 1].into_iter().collect();
assert!(a0 == a1 && a0.to_string() == "1..=3, 100..=100");

// 'from_iter'/'collect': From an iterator of inclusive ranges, start..=end.
// Overlapping, out-of-order, and empty ranges are fine.
#[allow(clippy::reversed_empty_ranges)]
let a0 = RangeSetBlaze::from_iter([1..=2, 2..=2, -10..=-5, 1..=0]);
#[allow(clippy::reversed_empty_ranges)]
let a1: RangeSetBlaze<i32> = [1..=2, 2..=2, -10..=-5, 1..=0].into_iter().collect();
assert!(a0 == a1 && a0.to_string() == "-10..=-5, 1..=2");

// 'from_slice': From any array-like collection of integers.
// Nightly-only, but faster than 'from_iter'/'collect' on integers.
#[cfg(feature = "from_slice")]
let a0 = RangeSetBlaze::from_slice(vec![3, 2, 1, 100, 1]);
#[cfg(feature = "from_slice")]
assert!(a0.to_string() == "1..=3, 100..=100");

// If we know the ranges are already sorted and disjoint,
// we can avoid work and use 'from'/'into'.
let a0 = RangeSetBlaze::from_sorted_disjoint(CheckSortedDisjoint::from([-10..=-5, 1..=2]));
let a1: RangeSetBlaze<i32> = CheckSortedDisjoint::from([-10..=-5, 1..=2]).into_range_set_blaze();
assert!(a0 == a1 && a0.to_string() == "-10..=-5, 1..=2");

// For compatibility with `BTreeSet`, we also support
// 'from'/'into' from arrays of integers.
let a0 = RangeSetBlaze::from([3, 2, 1, 100, 1]);
let a1: RangeSetBlaze<i32> = [3, 2, 1, 100, 1].into();
assert!(a0 == a1 && a0.to_string() == "1..=3, 100..=100");

RangeSetBlaze Set Operations

You can perform set operations on RangeSetBlazes using operators.

Set Operation Operator Multiway Method
union a | b [a, b, c].union()
intersection a & b [a, b, c].intersection()
difference a - b n/a
symmetric difference a ^ b n/a
complement !a n/a

RangeSetBlaze also implements many other methods, such as [insert], [pop_first] and [split_off]. Many of these methods match those of BTreeSet.

Set Operation Performance

Every operation is implemented as

  1. a single pass over the sorted & disjoint ranges
  2. the construction of a new RangeSetBlaze

Thus, applying multiple operators creates intermediate RangeSetBlaze’s. If you wish, you can avoid these intermediate RangeSetBlaze’s by switching to the SortedDisjoint API. The last example below demonstrates this.

Set Operation Examples

use range_set_blaze::prelude::*;

let a = RangeSetBlaze::from_iter([1..=2, 5..=100]);
let b = RangeSetBlaze::from_iter([2..=6]);

// Union of two 'RangeSetBlaze's.
let result = &a | &b;
// Alternatively, we can take ownership via 'a | b'.
assert_eq!(result.to_string(), "1..=100");

// Intersection of two 'RangeSetBlaze's.
let result = &a & &b; // Alternatively, 'a & b'.
assert_eq!(result.to_string(), "2..=2, 5..=6");

// Set difference of two 'RangeSetBlaze's.
let result = &a - &b; // Alternatively, 'a - b'.
assert_eq!(result.to_string(), "1..=1, 7..=100");

// Symmetric difference of two 'RangeSetBlaze's.
let result = &a ^ &b; // Alternatively, 'a ^ b'.
assert_eq!(result.to_string(), "1..=1, 3..=4, 7..=100");

// complement of a 'RangeSetBlaze'.
let result = !&a; // Alternatively, '!a'.
assert_eq!(
    result.to_string(),
    "-2147483648..=0, 3..=4, 101..=2147483647"
);

// Multiway union of 'RangeSetBlaze's.
let c = RangeSetBlaze::from_iter([2..=2, 6..=200]);
let result = [&a, &b, &c].union();
assert_eq!(result.to_string(), "1..=200");

// Multiway intersection of 'RangeSetBlaze's.
let result = [&a, &b, &c].intersection();
assert_eq!(result.to_string(), "2..=2, 6..=6");

// Applying multiple operators
let result0 = &a - (&b | &c); // Creates an intermediate 'RangeSetBlaze'.
// Alternatively, we can use the 'SortedDisjoint' API and avoid the intermediate 'RangeSetBlaze'.
let result1 = RangeSetBlaze::from_sorted_disjoint(a.ranges() - (b.ranges() | c.ranges()));
assert!(result0 == result1 && result0.to_string() == "1..=1");

RangeSetBlaze Comparisons

We can compare RangeSetBlazes using the following operators: <, <=, >, >=. Following the convention of BTreeSet, these comparisons are lexicographic. See [cmp] for more examples.

Use the [is_subset] and [is_superset] methods to check if one RangeSetBlaze is a subset or superset of another.

Use ==, != to check if two RangeSetBlazes are equal or not.

Additional Examples

See the module-level documentation for additional examples.

flate2::Compression
fn default() -> Compression

Returns the “default value” for a type.

Default values are often some kind of initial value, identity value, or anything else that may make sense as a default.

Examples

Using built-in default values:

let i: i8 = Default::default();
let (x, y): (Option<String>, f64) = Default::default();
let (a, b, (c, d)): (i32, u32, (bool, bool)) = Default::default();

Making your own:

enum Kind {
    A,
    B,
    C,
}

impl Default for Kind {
    fn default() -> Self { Kind::A }
}
alloc::string
pub struct String {
    vec: Vec<u8>,
}

A UTF-8–encoded, growable string.

String is the most common string type. It has ownership over the contents of the string, stored in a heap-allocated buffer (see Representation). It is closely related to its borrowed counterpart, the primitive [str].

Examples

You can create a String from a literal string with [String::from]:

let hello = String::from("Hello, world!");

You can append a char to a String with the [push] method, and append a [&str] with the [push_str] method:

let mut hello = String::from("Hello, ");

hello.push('w');
hello.push_str("orld!");

If you have a vector of UTF-8 bytes, you can create a String from it with the [from_utf8] method:

// some bytes, in a vector
let sparkle_heart = vec![240, 159, 146, 150];

// We know these bytes are valid, so we'll use `unwrap()`.
let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();

assert_eq!("💖", sparkle_heart);

UTF-8

Strings are always valid UTF-8. If you need a non-UTF-8 string, consider OsString. It is similar, but without the UTF-8 constraint. Because UTF-8 is a variable width encoding, Strings are typically smaller than an array of the same chars:

use std::mem;

// `s` is ASCII which represents each `char` as one byte
let s = "hello";
assert_eq!(s.len(), 5);

// A `char` array with the same contents would be longer because
// every `char` is four bytes
let s = ['h', 'e', 'l', 'l', 'o'];
let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
assert_eq!(size, 20);

// However, for non-ASCII strings, the difference will be smaller
// and sometimes they are the same
let s = "💖💖💖💖💖";
assert_eq!(s.len(), 20);

let s = ['💖', '💖', '💖', '💖', '💖'];
let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum();
assert_eq!(size, 20);

This raises interesting questions as to how s[i] should work. What should i be here? Several options include byte indices and char indices but, because of UTF-8 encoding, only byte indices would provide constant time indexing. Getting the ith char, for example, is available using [chars]:

let s = "hello";
let third_character = s.chars().nth(2);
assert_eq!(third_character, Some('l'));

let s = "💖💖💖💖💖";
let third_character = s.chars().nth(2);
assert_eq!(third_character, Some('💖'));

Next, what should s[i] return? Because indexing returns a reference to underlying data it could be &u8, &[u8], or something else similar. Since we’re only providing one index, &u8 makes the most sense but that might not be what the user expects and can be explicitly achieved with [as_bytes()]:

// The first byte is 104 - the byte value of `'h'`
let s = "hello";
assert_eq!(s.as_bytes()[0], 104);
// or
assert_eq!(s.as_bytes()[0], b'h');

// The first byte is 240 which isn't obviously useful
let s = "💖💖💖💖💖";
assert_eq!(s.as_bytes()[0], 240);

Due to these ambiguities/restrictions, indexing with a usize is simply forbidden:

let s = "hello";

// The following will not compile!
println!("The first letter of s is {}", s[0]);

It is more clear, however, how &s[i..j] should work (that is, indexing with a range). It should accept byte indices (to be constant-time) and return a &str which is UTF-8 encoded. This is also called “string slicing”. Note this will panic if the byte indices provided are not character boundaries - see [is_char_boundary] for more details. See the implementations for [SliceIndex<str>] for more details on string slicing. For a non-panicking version of string slicing, see [get].

The [bytes] and [chars] methods return iterators over the bytes and codepoints of the string, respectively. To iterate over codepoints along with byte indices, use [char_indices].

Deref

String implements [Deref]<Target = [str]>, and so inherits all of [str]’s methods. In addition, this means that you can pass a String to a function which takes a [&str] by using an ampersand (&):

fn takes_str(s: &str) { }

let s = String::from("Hello");

takes_str(&s);

This will create a [&str] from the String and pass it in. This conversion is very inexpensive, and so generally, functions will accept [&str]s as arguments unless they need a String for some specific reason.

In certain cases Rust doesn’t have enough information to make this conversion, known as [Deref] coercion. In the following example a string slice &'a str implements the trait TraitExample, and the function example_func takes anything that implements the trait. In this case Rust would need to make two implicit conversions, which Rust doesn’t have the means to do. For that reason, the following example will not compile.

trait TraitExample {}

impl<'a> TraitExample for &'a str {}

fn example_func<A: TraitExample>(example_arg: A) {}

let example_string = String::from("example_string");
example_func(&example_string);

There are two options that would work instead. The first would be to change the line example_func(&example_string); to example_func(example_string.as_str());, using the method [as_str] to explicitly extract the string slice containing the string. The second way changes example_func(&example_string); to example_func(&*example_string);. In this case we are dereferencing a String to a [str], then referencing the [str] back to [&str]. The second way is more idiomatic, however both work to do the conversion explicitly rather than relying on the implicit conversion.

Representation

A String is made up of three components: a pointer to some bytes, a length, and a capacity. The pointer points to the internal buffer which String uses to store its data. The length is the number of bytes currently stored in the buffer, and the capacity is the size of the buffer in bytes. As such, the length will always be less than or equal to the capacity.

This buffer is always stored on the heap.

You can look at these with the [as_ptr], [len], and [capacity] methods:

use std::mem;

let story = String::from("Once upon a time...");

// Prevent automatically dropping the String's data
let mut story = mem::ManuallyDrop::new(story);

let ptr = story.as_mut_ptr();
let len = story.len();
let capacity = story.capacity();

// story has nineteen bytes
assert_eq!(19, len);

// We can re-build a String out of ptr, len, and capacity. This is all
// unsafe because we are responsible for making sure the components are
// valid:
let s = unsafe { String::from_raw_parts(ptr, len, capacity) } ;

assert_eq!(String::from("Once upon a time..."), s);

If a String has enough capacity, adding elements to it will not re-allocate. For example, consider this program:

let mut s = String::new();

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

This will output the following:

0
8
16
16
32
32

At first, we have no memory allocated at all, but as we append to the string, it increases its capacity appropriately. If we instead use the [with_capacity] method to allocate the correct capacity initially:

let mut s = String::with_capacity(25);

println!("{}", s.capacity());

for _ in 0..5 {
    s.push_str("hello");
    println!("{}", s.capacity());
}

We end up with a different output:

25
25
25
25
25
25

Here, there’s no need to allocate more memory inside the loop.

let sep: impl FnMut(&str) -> Result<(&str, &str), Err<Error<&str>>>
alloc::vec
pub struct Vec<T, A = Global>
where
    A: Allocator,
{
    buf: RawVec<T, A>,
    len: usize,
}

A contiguous growable array type, written as Vec<T>, short for ‘vector’.

Examples

let mut vec = Vec::new();
vec.push(1);
vec.push(2);

assert_eq!(vec.len(), 2);
assert_eq!(vec[0], 1);

assert_eq!(vec.pop(), Some(2));
assert_eq!(vec.len(), 1);

vec[0] = 7;
assert_eq!(vec[0], 7);

vec.extend([1, 2, 3]);

for x in &vec {
    println!("{x}");
}
assert_eq!(vec, [7, 1, 2, 3]);

The vec macro is provided for convenient initialization:

let mut vec1 = vec![1, 2, 3];
vec1.push(4);
let vec2 = Vec::from([1, 2, 3, 4]);
assert_eq!(vec1, vec2);

It can also initialize each element of a Vec<T> with a given value. This may be more efficient than performing allocation and initialization in separate steps, especially when initializing a vector of zeros:

let vec = vec![0; 5];
assert_eq!(vec, [0, 0, 0, 0, 0]);

// The following is equivalent, but potentially slower:
let mut vec = Vec::with_capacity(5);
vec.resize(5, 0);
assert_eq!(vec, [0, 0, 0, 0, 0]);

For more information, see Capacity and Reallocation.

Use a Vec<T> as an efficient stack:

let mut stack = Vec::new();

stack.push(1);
stack.push(2);
stack.push(3);

while let Some(top) = stack.pop() {
    // Prints 3, 2, 1
    println!("{top}");
}

Indexing

The Vec type allows access to values by index, because it implements the Index trait. An example will be more explicit:

let v = vec![0, 2, 4, 6];
println!("{}", v[1]); // it will display '2'

However be careful: if you try to access an index which isn’t in the Vec, your software will panic! You cannot do this:

let v = vec![0, 2, 4, 6];
println!("{}", v[6]); // it will panic!

Use [get] and [get_mut] if you want to check whether the index is in the Vec.

Slicing

A Vec can be mutable. On the other hand, slices are read-only objects. To get a slice, use &. Example:

fn read_slice(slice: &[usize]) {
    // ...
}

let v = vec![0, 1];
read_slice(&v);

// ... and that's all!
// you can also do it like this:
let u: &[usize] = &v;
// or like this:
let u: &[_] = &v;

In Rust, it’s more common to pass slices as arguments rather than vectors when you just want to provide read access. The same goes for [String] and [&str].

Capacity and reallocation

The capacity of a vector is the amount of space allocated for any future elements that will be added onto the vector. This is not to be confused with the length of a vector, which specifies the number of actual elements within the vector. If a vector’s length exceeds its capacity, its capacity will automatically be increased, but its elements will have to be reallocated.

For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or cause reallocation to occur. However, if the vector’s length is increased to 11, it will have to reallocate, which can be slow. For this reason, it is recommended to use Vec::with_capacity whenever possible to specify how big the vector is expected to get.

Guarantees

Due to its incredibly fundamental nature, Vec makes a lot of guarantees about its design. This ensures that it’s as low-overhead as possible in the general case, and can be correctly manipulated in primitive ways by unsafe code. Note that these guarantees refer to an unqualified Vec<T>. If additional type parameters are added (e.g., to support custom allocators), overriding their defaults may change the behavior.

Most fundamentally, Vec is and always will be a (pointer, capacity, length) triplet. No more, no less. The order of these fields is completely unspecified, and you should use the appropriate methods to modify these. The pointer will never be null, so this type is null-pointer-optimized.

However, the pointer might not actually point to allocated memory. In particular, if you construct a Vec with capacity 0 via Vec::new, vec![], Vec::with_capacity(0), or by calling [shrink_to_fit] on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized types inside a Vec, it will not allocate space for them. Note that in this case the Vec might not report a [capacity] of 0. Vec will allocate if and only if mem::size_of::<T>() * capacity > 0. In general, Vec’s allocation details are very subtle — if you intend to allocate memory using a Vec and use it for something else (either to pass to unsafe code, or to build your own memory-backed collection), be sure to deallocate this memory by using from_raw_parts to recover the Vec and then dropping it.

If a Vec has allocated memory, then the memory it points to is on the heap (as defined by the allocator Rust is configured to use by default), and its pointer points to [len] initialized, contiguous elements in order (what you would see if you coerced it to a slice), followed by [capacity] - [len] logically uninitialized, contiguous elements.

A vector containing the elements 'a' and 'b' with capacity 4 can be visualized as below. The top part is the Vec struct, it contains a pointer to the head of the allocation in the heap, length and capacity. The bottom part is the allocation on the heap, a contiguous memory block.

            ptr      len  capacity
       +--------+--------+--------+
       | 0x0123 |      2 |      4 |
       +--------+--------+--------+
            |
            v
Heap   +--------+--------+--------+--------+
       |    'a' |    'b' | uninit | uninit |
       +--------+--------+--------+--------+
  • uninit represents memory that is not initialized, see [MaybeUninit].
  • Note: the ABI is not stable and Vec makes no guarantees about its memory layout (including the order of fields).

Vec will never perform a “small optimization” where elements are actually stored on the stack for two reasons:

  • It would make it more difficult for unsafe code to correctly manipulate a Vec. The contents of a Vec wouldn’t have a stable address if it were only moved, and it would be more difficult to determine if a Vec had actually allocated memory.

  • It would penalize the general case, incurring an additional branch on every access.

Vec will never automatically shrink itself, even if completely empty. This ensures no unnecessary allocations or deallocations occur. Emptying a Vec and then filling it back up to the same [len] should incur no calls to the allocator. If you wish to free up unused memory, use [shrink_to_fit] or [shrink_to].

[push] and [insert] will never (re)allocate if the reported capacity is sufficient. [push] and [insert] will (re)allocate if [len] == [capacity]. That is, the reported capacity is completely accurate, and can be relied on. It can even be used to manually free the memory allocated by a Vec if desired. Bulk insertion methods may reallocate, even when not necessary.

Vec does not guarantee any particular growth strategy when reallocating when full, nor when [reserve] is called. The current strategy is basic and it may prove desirable to use a non-constant growth factor. Whatever strategy is used will of course guarantee O(1) amortized [push].

vec![x; n], vec![a, b, c, d], and Vec::with_capacity(n), will all produce a Vec with at least the requested capacity. If [len] == [capacity], (as is the case for the vec macro), then a Vec<T> can be converted to and from a Box<[T]> without reallocating or moving the elements.

Vec will not specifically overwrite any data that is removed from it, but also won’t specifically preserve it. Its uninitialized memory is scratch space that it may use however it wants. It will generally just do whatever is most efficient or otherwise easy to implement. Do not rely on removed data to be erased for security purposes. Even if you drop a Vec, its buffer may simply be reused by another allocation. Even if you zero a Vec’s memory first, that might not actually happen because the optimizer does not consider this a side-effect that must be preserved. There is one case which we will not break, however: using unsafe code to write to the excess capacity, and then increasing the length to match, is always valid.

Currently, Vec does not guarantee the order in which elements are dropped. The order has changed in the past and may change again.

core::str
pub fn trim(&self) -> &str

Returns a string slice with leading and trailing whitespace removed.

‘Whitespace’ is defined according to the terms of the Unicode Derived Core Property White_Space, which includes newlines.

Examples

let s = "\n Hello\tworld\t\n";

assert_eq!("Hello\tworld", s.trim());
flate2::zlib::write::ZlibEncoder
impl<W> ZlibEncoder<W>
pub fn new(w: W, level: crate::Compression) -> ZlibEncoder<W>
where
    // Bounds from impl:
    W: Write,

Creates a new encoder which will write compressed data to the stream given at the given compression level.

When this encoder is dropped or unwrapped the final pieces of data will be flushed.

src
pub struct Rc<T, A = Global>
where
    T: ?Sized,
    A: Allocator,
{
    ptr: NonNull<RcBox<T>>,
    phantom: PhantomData<RcBox<T>>,
    alloc: A,
}
lang: &str
nom::combinator
pub fn map_res<I, O1, O2, E, E2, F, G>(mut parser: F, mut f: G) -> impl FnMut(I) -> IResult<I, O2, E>
where
    I: Clone,
    E: FromExternalError<I, E2>,
    F: Parser<I, O1, E>,
    G: FnMut(O1) -> Result<O2, E2>,

Applies a function returning a Result over the result of a parser.

use nom::character::complete::digit1;
use nom::combinator::map_res;

let mut parse = map_res(digit1, |s: &str| s.parse::<u8>());

// the parser will convert the result of digit1 to a number
assert_eq!(parse("123"), Ok(("", 123)));

// this will fail if digit1 fails
assert_eq!(parse("abc"), Err(Err::Error(("abc", ErrorKind::Digit))));

// this will fail if the mapped function fails (a `u8` is too small to hold `123456`)
assert_eq!(parse("123456"), Err(Err::Error(("123456", ErrorKind::MapRes))));
nom::combinator
pub fn all_consuming<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, O, E>
where
    E: ParseError<I>,
    I: InputLength,
    F: Parser<I, O, E>,

Succeeds if all the input has been consumed by its child parser.

use nom::combinator::all_consuming;
use nom::character::complete::alpha1;

let mut parser = all_consuming(alpha1);

assert_eq!(parser("abcd"), Ok(("", "abcd")));
assert_eq!(parser("abcd;"),Err(Err::Error((";", ErrorKind::Eof))));
assert_eq!(parser("123abcd;"),Err(Err::Error(("123abcd;", ErrorKind::Alpha))));
src
fn digits_exact(input: &str) -> nom::IResult<&str, usize>
let args: Value
self: &RangeSet
core::option
pub enum Option<T> {
    None,
    Some( /* … */ ),
}

The Option type. See the module level documentation for more.

flate2::zlib::write
pub struct ZlibEncoder<W>
where
    W: Write,
{
    inner: Writer<W, Compress>,
}

A ZLIB encoder, or compressor.

This structure implements a Write interface and takes a stream of uncompressed data, writing the compressed data to the wrapped writer.

Examples

use std::io::prelude::*;
use flate2::Compression;
use flate2::write::ZlibEncoder;

// Vec<u8> implements Write, assigning the compressed bytes of sample string

let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
e.write_all(b"Hello World")?;
let compressed = e.finish()?;
core::iter::traits::iterator::Iterator
pub trait Iterator
pub fn map<B, F>(self, f: F) -> Map<Self, F>
where
    Self: Sized,
    F: FnMut(Self::Item) -> B,

Takes a closure and creates an iterator which calls that closure on each element.

map() transforms one iterator into another, by means of its argument: something that implements FnMut. It produces a new iterator which calls this closure on each element of the original iterator.

If you are good at thinking in types, you can think of map() like this: If you have an iterator that gives you elements of some type A, and you want an iterator of some other type B, you can use map(), passing a closure that takes an A and returns a B.

map() is conceptually similar to a for loop. However, as map() is lazy, it is best used when you’re already working with other iterators. If you’re doing some sort of looping for a side effect, it’s considered more idiomatic to use for than map().

Examples

Basic usage:

let a = [1, 2, 3];

let mut iter = a.iter().map(|x| 2 * x);

assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(4));
assert_eq!(iter.next(), Some(6));
assert_eq!(iter.next(), None);

If you’re doing some sort of side effect, prefer for to map():

// don't do this:
(0..5).map(|x| println!("{x}"));

// it won't even execute, as it is lazy. Rust will warn you about this.

// Instead, use for:
for x in 0..5 {
    println!("{x}");
}
let result: (Option<usize>, &str, Option<usize>)
s: &str
std::io::Write
pub trait Write
pub fn write_all(&mut self, mut buf: &[u8]) -> Result<()>

Attempts to write an entire buffer into this writer.

This method will continuously call [write] until there is no more data to be written or an error of non-ErrorKind::Interrupted kind is returned. This method will not return until the entire buffer has been successfully written or such an error occurs. The first error that is not of ErrorKind::Interrupted kind generated from this method will be returned.

If the buffer contains no data, this will never call [write].

Errors

This function will return the first error of non-ErrorKind::Interrupted kind that [write] returns.

Examples

use std::io::prelude::*;
use std::fs::File;

fn main() -> std::io::Result<()> {
    let mut buffer = File::create("foo.txt")?;

    buffer.write_all(b"some bytes")?;
    Ok(())
}
core::marker
// Dyn Compatible: Yes
pub trait Sized

Types with a constant size known at compile time.

All type parameters have an implicit bound of Sized. The special syntax ?Sized can be used to remove this bound if it’s not appropriate.

struct Foo<T>(T);
struct Bar<T: ?Sized>(T);

// struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
struct BarUse(Bar<[i32]>); // OK

The one exception is the implicit Self type of a trait. A trait does not have an implicit Sized bound as this is incompatible with trait objects where, by definition, the trait needs to work with all possible implementors, and thus could be any size.

Although Rust will let you bind Sized to a trait, you won’t be able to use it to form a trait object later:

trait Foo { }
trait Bar: Sized { }

struct Impl;
impl Foo for Impl { }
impl Bar for Impl { }

let x: &dyn Foo = &Impl;    // OK
// let y: &dyn Bar = &Impl; // error: the trait `Bar` cannot
                            // be made into an object
base64::engine::Engine
pub trait Engine
pub fn encode_string<T>(&self, input: T, output_buf: &mut String)
where
    T: AsRef<[u8]>,
    // Bounds from trait:
    Self: Send + Sync,

Encode arbitrary octets as base64 into a supplied String. Writes into the supplied String, which may allocate if its internal buffer isn’t big enough.

Example

use base64::{Engine as _, engine::{self, general_purpose}, alphabet};
const CUSTOM_ENGINE: engine::GeneralPurpose =
    engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::NO_PAD);

fn main() {
    let mut buf = String::new();
    general_purpose::STANDARD.encode_string(b"hello world~", &mut buf);
    println!("{}", buf);

    buf.clear();
    CUSTOM_ENGINE.encode_string(b"hello internet~", &mut buf);
    println!("{}", buf);
}
core::result::Result
Err(E)

Contains the error value

src::RcBox
value: T
src
fn range(input: &str) -> nom::IResult<&str, (Option<usize>, &str, Option<usize>)>
flate2::zlib::write::ZlibEncoder
impl<W> ZlibEncoder<W>
pub fn finish(self) -> io::Result<W>
where
    // Bounds from impl:
    W: Write,

Consumes this encoder, flushing the output stream.

This will flush the underlying data stream, close off the compressed stream and, if successful, return the contained writer.

Note that this function may not be suitable to call in a situation where the underlying stream is an asynchronous I/O stream. To finish a stream the try_finish (or shutdown) method should be used instead. To re-acquire ownership of a stream it is safe to call this method after try_finish or shutdown has returned Ok.

Errors

This function will perform I/O to complete this stream, and any I/O errors which occur will be returned from this function.

core::str
pub fn parse<F>(&self) -> Result<F, F::Err>
where
    F: FromStr,

Parses this string slice into another type.

Because parse is so general, it can cause problems with type inference. As such, parse is one of the few times you’ll see the syntax affectionately known as the ‘turbofish’: ::<>. This helps the inference algorithm understand specifically which type you’re trying to parse into.

parse can parse into any type that implements the FromStr trait.

Errors

Will return [Err] if it’s not possible to parse this string slice into the desired type.

Examples

Basic usage

let four: u32 = "4".parse().unwrap();

assert_eq!(4, four);

Using the ‘turbofish’ instead of annotating four:

let four = "4".parse::<u32>();

assert_eq!(Ok(4), four);

Failing to parse:

let nope = "j".parse::<u32>();

assert!(nope.is_err());
let mut rangeset: RangeSet
input: &str
core::macros::builtin
macro derive

Attribute macro used to apply derive macros.

See the reference for more info.

core::result::Result
impl<T, E> Result<T, E>
pub fn map_err<F, O>(self, op: O) -> Result<T, F>
where
    O: FnOnce(E) -> F,

Maps a Result<T, E> to Result<T, F> by applying a function to a contained Err value, leaving an Ok value untouched.

This function can be used to pass through a successful result while handling an error.

Examples

fn stringify(x: u32) -> String { format!("error code: {x}") }

let x: Result<u32, u32> = Ok(2);
assert_eq!(x.map_err(stringify), Ok(2));

let x: Result<u32, u32> = Err(13);
assert_eq!(x.map_err(stringify), Err("error code: 13".to_string()));
let right: usize
core::macros::builtin
macro_rules! file

Expands to the file name in which it was invoked.

With line and column, these macros provide debugging information for developers about the location within the source.

The expanded expression has type &'static str, and the returned file is not the invocation of the file! macro itself, but rather the first macro invocation leading up to the invocation of the file! macro.

Examples

let this_file = file!();
println!("defined in file: {this_file}");
src::Rc
ptr: NonNull<RcBox<T>>
str

String slices.

See also the std::str module.

The str type, also called a ‘string slice’, is the most primitive string type. It is usually seen in its borrowed form, &str. It is also the type of string literals, &'static str.

Basic Usage

String literals are string slices:

let hello_world = "Hello, World!";

Here we have declared a string slice initialized with a string literal. String literals have a static lifetime, which means the string hello_world is guaranteed to be valid for the duration of the entire program. We can explicitly specify hello_world’s lifetime as well:

let hello_world: &'static str = "Hello, world!";

Representation

A &str is made up of two components: a pointer to some bytes, and a length. You can look at these with the [as_ptr] and [len] methods:

use std::slice;
use std::str;

let story = "Once upon a time...";

let ptr = story.as_ptr();
let len = story.len();

// story has nineteen bytes
assert_eq!(19, len);

// We can re-build a str out of ptr and len. This is all unsafe because
// we are responsible for making sure the two components are valid:
let s = unsafe {
    // First, we build a &[u8]...
    let slice = slice::from_raw_parts(ptr, len);

    // ... and then convert that slice into a string slice
    str::from_utf8(slice)
};

assert_eq!(s, Ok(story));

Note: This example shows the internals of &str. unsafe should not be used to get a string slice under normal circumstances. Use as_str instead.

Invariant

Rust libraries may assume that string slices are always valid UTF-8.

Constructing a non-UTF-8 string slice is not immediate undefined behavior, but any function called on a string slice may assume that it is valid UTF-8, which means that a non-UTF-8 string slice can lead to undefined behavior down the road.

let left: usize
src::Rc
phantom: PhantomData<RcBox<T>>
alloc::vec::Vec
impl<T> Vec<T, Global>
pub const fn new() -> Self

Constructs a new, empty Vec<T>.

The vector will not allocate until elements are pushed onto it.

Examples

let mut vec: Vec<i32> = Vec::new();
src::RangeSet
fn default() -> Self

Returns the “default value” for a type.

Default values are often some kind of initial value, identity value, or anything else that may make sense as a default.

Examples

Using built-in default values:

let i: i8 = Default::default();
let (x, y): (Option<String>, f64) = Default::default();
let (a, b, (c, d)): (i32, u32, (bool, bool)) = Default::default();

Making your own:

enum Kind {
    A,
    B,
    C,
}

impl Default for Kind {
    fn default() -> Self { Kind::A }
}