Skip to main content

Out

Struct Out 

Source
pub struct Out { /* private fields */ }
Expand description

A reply buffer for one connection.

Owns its bytes so that a connection can fill it across several commands and hand the whole thing to one write, which is 04 section 5: one writev per connection per batch, not one per reply.

Implementations§

Source§

impl Out

Source

pub fn new(proto: Proto) -> Out

An empty buffer speaking proto.

Source

pub fn with_capacity(proto: Proto, cap: usize) -> Out

An empty buffer with room already reserved.

Source

pub const fn proto(&self) -> Proto

The protocol this connection is speaking.

Source

pub const fn set_proto(&mut self, proto: Proto)

Switches protocol, which is what HELLO does.

Takes effect from the next reply written. HELLO’s own reply is written in the new protocol, which is why this is called before it rather than after.

Source

pub fn as_slice(&self) -> &[u8]

The bytes written so far.

Source

pub fn len(&self) -> usize

How many bytes are pending.

Source

pub fn capacity(&self) -> usize

How much room it is holding, which is what it costs the process.

A reply buffer keeps its capacity between batches on purpose, so len is what a client is owed and this is what the memory report owes.

Source

pub fn is_empty(&self) -> bool

Whether nothing is pending.

Source

pub fn clear(&mut self)

Drops everything written, keeping the capacity.

Called after the batch has been written to the socket. The capacity is what stops a busy connection from allocating again.

Source

pub fn consume(&mut self, n: usize)

Drops the first n bytes, which is what a partial write leaves behind.

§Panics

If n is past the end of what has been written.

Source

pub fn truncate(&mut self, len: usize)

Drops everything written after len, which has to be a length this buffer reported earlier.

The dispatcher takes the length before it runs a command and rolls back to it when the command answers with an error, so a command that writes half a reply and then fails cannot leave the half on the wire. Every command is written to check its arguments before it writes anything, and this is what makes that a property of the dispatcher rather than a rule three hundred commands have to keep to.

Source

pub fn reserve(&mut self, n: usize)

Reserves room for n more bytes.

The presize half of Y18. Call it once with the whole reply’s size before writing any of it.

Source

pub fn into_inner(self) -> Vec<u8>

The buffer, taken.

Source

pub fn raw(&mut self, bytes: &[u8])

Raw bytes, appended as they are.

For a reply that was assembled elsewhere, such as a cached COMMAND DOCS payload or a replicated frame passing through. Nothing checks that what goes in is a valid frame, which is the point.

Source

pub fn simple(&mut self, s: &[u8])

A simple string, +s\r\n. No CR or LF may appear in s.

Source

pub fn ok(&mut self)

+OK\r\n, which is most of what a write command replies.

Source

pub fn error(&mut self, msg: &[u8])

An error, -msg\r\n.

msg carries its own prefix, because the prefix is part of the contract: a client branches on WRONGTYPE or MOVED or NOAUTH, and which one applies is the command’s decision and not the codec’s. The full taxonomy is in 12 section 1.

Source

pub fn error_line(&mut self, prefix: &[u8], msg: &[u8])

An error built from a prefix and a message that are not next to each other in memory, with any line ending in the message turned into a space.

The prefix carries its own trailing space, so this is called with b"ERR " or b"WRONGTYPE ". Joining the two halves first would mean allocating a string on the failure path of a thread that is not allowed to allocate, which is the whole reason this exists.

The mapping of \r and \n to spaces is Redis’s, and it is not cosmetic: an error message can quote what the client sent, and a client that sends a command name with a newline in it would otherwise be writing its own frames into somebody’s reply stream.

Source

pub fn blob_error(&mut self, msg: &[u8])

A blob error, RESP3’s !, which may carry anything including newlines.

Degrades to a normal error line in RESP2, with line endings turned into spaces, because a RESP2 error is one line by definition.

Source

pub fn int(&mut self, n: i64)

An integer, :n\r\n.

Source

pub fn uint(&mut self, n: u64)

An unsigned integer, :n\r\n.

Not the same as Out::int for the numbers with bit 63 set, and that is the only reason it exists. ARLEN on a key with something at the top of the index space is eighteen quintillion, which the signed path would put on the wire as a negative number. Redis has the same pair of writers and uses the unsigned one for exactly these replies.

Source

pub fn bulk(&mut self, s: &[u8])

A bulk string, $len\r\n...\r\n.

Source

pub fn bulk_int(&mut self, n: i64)

A bulk string holding the decimal form of n.

Written straight into the buffer rather than through a temporary, which is worth having as its own method because several commands reply with a number as a string and every one of them would otherwise allocate.

Source

pub fn bulk_u64(&mut self, n: u64)

A bulk string holding the decimal form of n, unsigned.

Not the same as Out::bulk_int for the numbers with bit 63 set, which is the only reason it exists: a scan cursor packs a partition count into the top bits, so a big enough collection hands back a number that the signed path would report as negative and no client would send back.

Source

pub fn bulk_double(&mut self, d: f64)

A bulk string holding a double in Redis’s own formatting.

A score written into a flat RESP2 reply arrives here rather than at Out::double, because there is no protocol choice left to make by then.

The length has to go in front of the digits and the digits cannot be counted without writing them, so they are written first, the header is appended behind them, and the two are rotated into place. A double is a couple of dozen bytes at most, so the rotate is a few words, and nothing is allocated to hold a number on its way into a buffer it is already in.

Source

pub fn human_double(&mut self, d: f64)

A bulk string holding a double the way the two float increments write one.

INCRBYFLOAT and HINCRBYFLOAT go through ld2string in its human mode where every other double goes through d2string, and the two disagree about large and small magnitudes: this one never writes an exponent. Both of them reply with a bulk string on RESP2 and on RESP3 alike, so unlike Out::double there is no protocol branch here.

Source

pub fn verbatim(&mut self, format: &[u8; 3], text: &[u8])

A verbatim string, RESP3’s =, with a three byte format such as txt or mkd.

RESP2 has no such type and gets a plain bulk string of the text, without the format prefix, which is what Redis does.

Source

pub fn big_number(&mut self, digits: &[u8])

A big number, RESP3’s (, given as its decimal digits.

RESP2 gets a bulk string of the same digits, which is what Redis does and what every client already handles.

Source

pub fn nil(&mut self)

Nothing, where a string was expected.

RESP3 has one null. RESP2 has two, and this is the one that stands in for a missing string, which is what GET on a missing key returns.

Source

pub fn nil_array(&mut self)

Nothing, where an array was expected.

The other RESP2 null. EXEC on a dirty WATCH returns this one, and a client that tells the two apart will notice if the wrong one is sent.

Source

pub fn double(&mut self, d: f64)

A double, RESP3’s ,.

RESP2 gets a bulk string of the same digits. The infinities and NaN are written as words in both.

Source

pub fn bool(&mut self, b: bool)

A boolean, RESP3’s #t or #f.

RESP2 gets :1 or :0, which is what every command that returns a boolean has always returned there.

Source

pub fn array(&mut self, n: usize)

An array header for n elements. The caller writes the elements next.

Source

pub fn hoist(&mut self, start: usize, tail: usize)

Move the last tail bytes back to start, so that something written after a reply ends up in front of it.

Not every reply knows how long it is before it has been written. SSCAN walks a window of the set and drops the members that do not match its pattern, so the count is only true once the last member has been looked at, and it answers with a cursor that the same walk produced. The alternatives are both worse: walking the window twice runs the glob twice, and collecting the members first is an allocation per call on a thread that must not allocate.

Redis solves this with a linked list of reply nodes it can patch in place. There is one flat buffer here, so the piece that belongs in front is written behind and the two are rotated past each other, which is the trick Out::bulk_double already uses and costs one move of bytes that were about to be moved to a socket anyway.

§Panics

If start is past the end, or tail is longer than what follows it.

Source

pub fn close_array(&mut self, start: usize, n: usize)

An array header for the elements written since start, which has to be a length this buffer reported earlier.

Out::hoist is why this can be called after the elements rather than before them.

Source

pub fn close_set(&mut self, start: usize, n: usize)

The same for a set, which is what the algebra commands answer.

SINTER cannot count its own reply in advance any more than SSCAN can. The answer is however many members survived a walk over the smallest set, and finding that out ahead of writing it means running the whole operation twice.

Source

pub fn map(&mut self, n: usize)

A map header for n pairs. The caller writes 2 * n elements next, key then value, n times.

RESP2 has no map and gets a flat array of twice as many elements, which is exactly what a RESP2 client already expects from HGETALL and CONFIG GET. The command does not know which one it wrote.

Source

pub fn set(&mut self, n: usize)

A set header for n elements.

RESP2 has no set and gets an array, which is what SMEMBERS has always returned there.

Source

pub fn push(&mut self, n: usize)

A push header for n elements, RESP3’s >.

This is how pub/sub messages and client side caching invalidations are delivered. RESP2 has no out of band type, so they go out as plain arrays on the same connection, which is how RESP2 pub/sub has always worked and is why a RESP2 connection in subscribe mode can only do a handful of things.

Source

pub fn attribute(&mut self, n: usize)

An attribute header for n pairs, RESP3’s |.

Attributes are metadata attached to the frame that follows. RESP2 cannot carry them at all, so the caller must check Out::proto before writing one. There is no downgrade, because turning metadata into a reply element would corrupt the reply.

§Panics

In debug, if the connection is not speaking RESP3.

Source

pub const fn bulk_len(value_len: usize) -> usize

The exact number of bytes Out::bulk would write for a value of this length.

Source

pub const fn int_len(n: i64) -> usize

The exact number of bytes Out::int would write.

Source

pub const fn header_len(n: usize) -> usize

The exact number of bytes an aggregate header of n elements would write, in either protocol, since both write one byte and the count.

Trait Implementations§

Source§

impl Clone for Out

Source§

fn clone(&self) -> Out

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Out

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Out

§

impl RefUnwindSafe for Out

§

impl Send for Out

§

impl Sync for Out

§

impl Unpin for Out

§

impl UnsafeUnpin for Out

§

impl UnwindSafe for Out

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.