frame
import std::net::ws::frame; · source
RFC 6455 section 5. A frame is a 2-byte header, an extended length (0, 2, or 8 bytes), an optional 4-byte masking key, then the payload.
Types
Reading and writing frames
implement struct BufStream<S> {
queue_frame(mut &this, fin: boolean, opcode: OpCode, payload: Slice<u8>, mask: boolean) -> Result<(), IoError>;
async read_frame(mut &this) -> Result<Frame, IoError>
where S: AsyncTransport;
}
Both directions are methods on BufStream<S>, beside HTTP/1.1's read_request and for the same reasons. Reading is a method because a parser written as a static taking mut &BufStream<S> cannot be called from an async caller holding the connection as a local; only the receiver is re-supplied on every poll. Queuing is synchronous: a whole frame — header, extended length, key, masked payload — is built into the connection's pending buffer with no suspension point inside it, and the caller suspends exactly once, in flush. The bytes are masked in place where they already sit, so no staging array is needed.
queue_frame applies a fresh masking key from the OS CSPRNG when the caller is a client and none when it is a server. read_frame rejects a reserved bit, an unknown opcode, or a payload beyond MAX_PAYLOAD (64 MiB) with InvalidData; no buffered() slice is held across an await, which is what makes the parse safe against a fill that grows and moves the connection's buffer.
Written once for BufStream<S> over any async transport, so ws:// over TcpStream and wss:// over TlsStream are served by the same code. You drive this through WebSocket; it is public so a different message layer could be built on the same framing.
Frame
type struct Frame {
fin: boolean;
opcode: OpCode;
masked: boolean;
payload: Array<u8>;
}
A decoded frame owns its payload; masked records whether the wire frame set the mask bit, so the connection layer — which knows whether it is the client or the server — can enforce the mask-direction rule.
Properties
| Property | Type |
|---|---|
fin | boolean |
opcode | OpCode |
masked | boolean |
payload | Array<u8> |
OpCode
type enum OpCode : u8 {
Continuation = 0x0;
Text = 0x1;
Binary = 0x2;
Close = 0x8;
Ping = 0x9;
Pong = 0xA;
}
The four-bit opcode. Text, Binary, and Continuation carry application data across a possibly fragmented message; Close, Ping, and Pong are control frames, never fragmented and at most 125 bytes.
Variants
| Variant |
|---|
Continuation = 0x0 |
Text = 0x1 |
Binary = 0x2 |
Close = 0x8 |
Ping = 0x9 |
Pong = 0xA |
Constants
const MAX_PAYLOAD: u64 = 67108864;implement struct Name { ... }
implement trait Trait for Type { ... }
implement u64 { ... }Adds methods to a type outside its declaration. implement struct T (or enum, or a bare primitive) opens an inherent block; implement trait Tr for T supplies a trait's methods for one type. Resolution is at compile time - no dynamic dispatch.
implement struct Name { ... }Names the struct an inherent block extends. The methods inside are interchangeable with ones declared in the struct body.
language referencetype struct BufStream<S> {
inner: S;
rbuf: Array<u8>;
rpos: u64;
scratch: Array<u8>;
wbuf: Array<u8>;
}type parameter SBufStream::queue_frame(mut &this, fin: boolean, opcode: OpCode, payload: Slice<u8>, mask: boolean) -> Result<(), IoError>Queue one frame into the outgoing buffer. mask selects client framing (a fresh masking key from the OS CSPRNG is generated and applied) from server framing (no mask), per RFC 6455 section 5.1. The payload is not consumed. Nothing is sent until the caller flushes.
mut &this
mut &TypeAn exclusive, mutating borrow. As a receiver, mut &this lets the method modify the fields - and callers can see that from the signature alone. As a parameter type, mut &T lets the callee mutate through the reference while the caller keeps ownership.
&this
mut &this
thisThe receiver of a method. Its first parameter declares how the method takes it: &this borrows read-only, mut &this borrows exclusively, and this / mut this move the value in and consume it. In the body, this.field reaches the members.
(parameter) fin: boolean(parameter) opcode: OpCodetype enum OpCode : u8 {
Continuation = 0x0;
Text = 0x1;
Binary = 0x2;
Close = 0x8;
Ping = 0x9;
Pong = 0xA;
}(parameter) payload: Slice<u8>type struct Slice<T> {
ptr: T*;
length: u64;
}Slice<T>: a borrowed view into a contiguous sequence.
std::core::slice(parameter) mask: booleanprimitive ()The unit type: a value that carries no information, and the empty tuple. Distinct from void, which is the absence of a value - Result<(), E> succeeds with nothing to return. 0 bytes.
type struct IoError {
kind: IoErrorKind;
os_code: i32;
}async function name(param: Type) -> T { ... }Compiles the function into a stackless state machine. Calling it builds a future whose output is the declared return type; nothing runs until that future is polled. Allowed on free functions, methods, and trait methods.
language referenceasync BufStream::read_frame(mut &this) -> Result<Frame, IoError>
where S: AsyncTransportRead one frame, enforcing the role-independent RFC 6455 framing rules: a set reserved bit (RSV1-3, section 5.2, no extension negotiated), an over-long or fragmented control frame (section 5.4-5.5), a reserved opcode, and an oversized payload are all rejected with InvalidData.
type struct Frame {
fin: boolean;
opcode: OpCode;
masked: boolean;
payload: Array<u8>;
}One decoded frame. Owns its payload bytes; call drop. masked records whether the wire frame set the mask bit, so the connection layer - which knows whether it is the client or the server - can enforce the RFC 6455 section 5.1 mask-direction rule (the frame reader itself is role-agnostic).
where T: Ord + Clone, U: HashConstrains generic parameters to types that implement the listed traits, which is what makes those traits' methods callable on T. Bounds on one parameter join with +; parameters separate with ,. A where on a single method narrows the type's parameter for that method only.
type parameter Stype trait AsyncTransport {
async read_into(mut &this, buf: Array<u8>) -> Transfer;
async write_from(mut &this, buf: Array<u8>) -> Transfer;
}One raw, unbuffered async byte channel: what BufStream<S> needs of a transport, and nothing more.
type struct Name { ... }
type enum Name { ... }
type trait Name { ... }
type union Name { ... }Begins a type declaration; the keyword that follows says which kind. On its own, type Name = Existing; declares an alias.
type struct Name {
field: Type;
method(&this) -> Ret { ... }
}A value type with named fields and optional methods. Structs live on the stack and are passed by value. Fields are public by default and may carry = default values; methods take their receiver as &this, mut &this, or this.
type struct Frame {
fin: boolean;
opcode: OpCode;
masked: boolean;
payload: Array<u8>;
}One decoded frame. Owns its payload bytes; call drop. masked records whether the wire frame set the mask bit, so the connection layer - which knows whether it is the client or the server - can enforce the RFC 6455 section 5.1 mask-direction rule (the frame reader itself is role-agnostic).
Frame.fin: booleanFrame.opcode: OpCodeFrame.masked: booleanFrame.payload: Array<u8>type struct Array<T, A = GlobalAlloc> where A: Allocator {
ptr: T*;
length: i64;
capacity: i64;
alloc: A;
}Array<T, A>: growable, heap-backed, contiguous sequence.
std::collections::arraytype enum Name {
Unit,
Payload(T),
Named { x: i32 },
}An algebraic data type. Variants may be bare or carry a tuple or struct payload, and a match on an enum must cover every variant. Name::Variant names a variant; methods are added with implement enum Name { ... }.
type enum OpCode : u8 {
Continuation = 0x0;
Text = 0x1;
Binary = 0x2;
Close = 0x8;
Ping = 0x9;
Pong = 0xA;
}OpCode::Continuation = 0x0OpCode::Text = 0x1OpCode::Binary = 0x2OpCode::Close = 0x8OpCode::Ping = 0x9OpCode::Pong = 0xAconst NAME: Type = value;At module level, a true compile-time constant, conventionally SCREAMING_SNAKE_CASE. (mut at module level declares mutable global state instead.)
const MAX_PAYLOAD: u64 = 67108864;import a::b;
import a::b::{ X, Y };
import a::b as c;
import a::b::*;Brings a module, or selected items from it, into scope. One path per declaration: use the brace form for several items, as to alias, and * for everything public (prefer the brace form; wildcards invite name collisions).
const MAX_PAYLOAD: u64 = 67108864;IoErrorKind::InvalidDataawait futureSuspends the enclosing async body until the operand - which must implement Future - completes, and evaluates to its output. A prefix operator allowed anywhere an expression is (conditions, arms, guards), but only inside async code.
type struct TcpStream {
fd: i32;
}type struct TlsStream {
ssl: void*;
inner: TcpStream;
}Frame.masked: booleanFrame.fin: booleanFrame.opcode: OpCodeFrame.payload: Array<u8>OpCode::Text = 0x1OpCode::Binary = 0x2OpCode::Continuation = 0x0OpCode::Close = 0x8OpCode::Ping = 0x9OpCode::Pong = 0xA