Struct io_context::Context [] [src]

pub struct Context { /* fields omitted */ }

A context that carries a deadline, cancelation signals and request scoped values across API boundaries and between processes.

A cancelation signal can be added using the add_cancel_signal method. Deadlines and timeouts can be added using the add_deadline and add_timeout methods. While add_value adds a value to the context.

For more information and examples see the crate level documentation.

Child contexts

A child context can be created by using the freeze method on the parent context, and then using the create_child method to create a child context. This should be done on a per request basis. This way each request has each own deadline and can be canceled if the connection is closed.

Any cancelation signals, deadlines, timeouts and values from the parent context will be shared between all the child contexts and all it's children, and it's children's children, etc. So if a parent context is canceled so are all it's children.

However adding or changing anything (like adding values or cancelation signals) on a child context will not affect the parent context. See the example below.

fn main() {
    // First create our parent context.
    let mut parent_ctx = Context::background();
    // We can use this `cancel_all` signal to handle ctrl-c.
    let parent_cancel_signal = parent_ctx.add_cancel_signal();
    // Now we freeze the parent context so it can be used to create child
    // contexts.
    let parent_ctx = parent_ctx.freeze();

    // Create child context from the parent context.
    let mut child_ctx = Context::create_child(&parent_ctx);
    // Add a cancel signal to the child context.
    let child_cancel_signal = child_ctx.add_cancel_signal();

    // Oh no! the connection was closed, now we need to cancel the child
    // context. This will only cancel the child context.
    child_cancel_signal.cancel();
    assert!(child_ctx.done().is_some());
    assert!(parent_ctx.done().is_none()); // Parent context is still going strong.

    // Now the user pressed ctrl-c and we'll cancel the parent context and
    // it's child context.
    parent_cancel_signal.cancel();
    assert!(child_ctx.done().is_some());
    assert!(parent_ctx.done().is_some());
}

Conventions

The context name is often shortend to ctx in code as seen in all the examples throughout the documentation of this crate. In documentation however the full word "context" is used.

Another convention is that the context is the first parameter of a function (after self), so it's easier to see if an API supports the context. See get_value for an example of this.

Contexts should not stored in structs, that is anti-pattern. Instead functions and methods that need a context should accept it as first parameter. This is also why Context does not implement common traits like Debug and Hash etc.

Methods

impl Context
[src]

Create an empty background context. It has no deadline or cancelation signals attached to it. It should be used as the top-level context of which children should be derived on a per request basis. See the crate documentation for a detailed example.

Add cancelation to the context. The signalthat is returned will cancel the context and it's children once called (see cancel). A single context can have multiple cancelation signals, after executing a cancelation the other signals will have no effect.

Add a deadline to the context. If the current deadline is sooner then the provided deadline this method does nothing.

See done for example usage.

A convience method to add a deadline to the context which is the current time plus the timeout.

See done for example usage.

Add a value to the context. It overwrites any previously set values with the same key. Because of this it's advised to keep key private in a library or module, see get_value for more.

This method does the same thing as add_value, but reuses the Box.

Get the deadline for this operation, if any. This is mainly useful for checking if a long job should be started or not, e.g. if a job takes 5 seconds to execute and only 1 second is left on the deadline we're better of skipping the job entirely.

If you only want to check if the deadline was exceeded use done instead. Because this also checks if the context was canceled.

Check if the context is done. If it returns None the operation may proceed. But if it returns something the operation should be stopped, this is the case if the context was canceled or if the deadline is exceeded.

Example

use std::time::Duration;

fn main() {
    let mut ctx = Context::background();
    ctx.add_timeout(Duration::from_secs(5));
    loop {
        // Do some work.
        do_some_work();

        // Check if the context deadline is exceeded, or if it was
        // canceled.
        if let Some(reason) = ctx.done() {
            println!("Stopping work because: {}", reason);
            break;
        }
    }
}

This does the same thing as done, but returns a Result instead so it can be used with the Try operator (?). For usage see the example below.

Example

use std::io;
use std::time::Duration;

fn main() {
    let mut ctx = Context::background();
    ctx.add_timeout(Duration::from_secs(5));
    loop {
        match do_some_work(&ctx) {
            Ok(()) => (),
            Err(err) => {
                println!("work stopped: {}", err);
                break;
            },
        }
    }
}

fn do_some_work(ctx: &Context) -> Result<(), io::Error> {
    ctx.is_done()?;

    // Do some work.
    Ok(())
}

Get a value from the context. If no value is stored in the Context under the provided key, or if the stored value doesn't have type V, this will return None.

Rather then letting the user of a library retrieve a value from the Context manually, a library or module should define add_to_context and get_from_context functions, like in the example below.

Example

In a library or module.

// The key used in `Context`. This should be private.
const REQUEST_ID_KEY: &'static str = "MY_LIBRARY_REQUEST_ID_KEY";

/// Add a `RequestId` to the provided `Context`.
pub fn add_request_id(ctx: &mut Context, request_id: RequestId) {
    ctx.add_value(REQUEST_ID_KEY, request_id)
}

/// Retrieve a `RequestId` from the provided `Context`.
pub fn get_request_id(ctx: &Context) -> Option<&RequestId> {
    ctx.get_value(REQUEST_ID_KEY)
}

In the application code.

fn main() {
    // Create our new context.
    let mut ctx = Context::background();
    // Add our `RequestId` to it.
    add_request_id(&mut ctx, 123);
    // Retrieve our `RequestId` later on.
    assert_eq!(get_request_id(&ctx), Some(123));
}

Freeze the Context so it can be used to create child contexts, see create_child. The parent context can no longer be modified after it's frozen and can only be used to create children.

See the Context documentation for an example.

Create a new child from a frozen Context, see freeze.

See the Context documentation for an example.

Trait Implementations

impl Debug for Context
[src]

Formats the value using the given formatter.