beryl/topic
Topic - Pattern matching for channel routing
Topics are string identifiers that clients join (e.g., "room:lobby"). Patterns define how topics are routed to channel handlers. Patterns can be exact, prefix wildcards, or segment wildcards where "*" occupies a complete colon-delimited segment.
ExtractError
Section titled “ExtractError”Errors from extracting wildcard values from a topic pattern.
pub type ExtractError { NoWildcard TopicMismatch ExpectedOneWildcard(Int) EmptyNamespace}Constructors
Section titled “Constructors”NoWildcard
Section titled “NoWildcard”The pattern has no wildcard to extract.
TopicMismatch
Section titled “TopicMismatch”The topic does not match the pattern.
ExpectedOneWildcard(Int)
Section titled “ExpectedOneWildcard(Int)”extract_id expected exactly one wildcard value but found this many.
EmptyNamespace
Section titled “EmptyNamespace”namespace was called with an empty topic.
TopicError
Section titled “TopicError”Errors returned when validating a topic or topic pattern.
pub type TopicError { EmptyTopic InvalidFormat(String)}Constructors
Section titled “Constructors”EmptyTopic
Section titled “EmptyTopic”The topic or pattern was an empty string.
InvalidFormat(String)
Section titled “InvalidFormat(String)”The topic, pattern, or event was malformed; the wrapped String
describes the problem (e.g. leading/trailing : or control characters).
TopicPattern
Section titled “TopicPattern”Topic pattern for routing
pub type TopicPattern { Exact(String) Wildcard(prefix: String) SegmentWildcard(segments: List(String))}Constructors
Section titled “Constructors”Exact(String)
Section titled “Exact(String)”Exact match: "room:lobby" only matches "room:lobby"
Wildcard(prefix: String)
Section titled “Wildcard(prefix: String)”Prefix wildcard: "room:*" matches "room:lobby", "room:123", etc.
SegmentWildcard(segments: List(String))
Section titled “SegmentWildcard(segments: List(String))”Segment wildcard: "document::ops" matches the same number of ":" segments where "" occupies one complete segment.
Functions
Section titled “Functions”extract_id
Section titled “extract_id”Extract the wildcard portion from a topic
Examples
Section titled “Examples”extract_id(Wildcard("room:"), "room:lobby") // -> Ok("lobby")extract_id(Wildcard("doc:"), "doc:abc:123") // -> Ok("abc:123")extract_id(SegmentWildcard(["doc", "*", "ops"]), "doc:abc:ops") // -> Ok("abc")extract_id(Exact("room:lobby"), "room:lobby") // -> Error(NoWildcard)pub fn extract_id( TopicPattern, String) -> Result(String, ExtractError)extract_wildcards
Section titled “extract_wildcards”Extract values captured by wildcard segments.
For prefix wildcards, returns the suffix as a single value. For segment wildcards, returns each topic segment matched by "*".
Examples
Section titled “Examples”extract_wildcards(parse_pattern("document:*:*"), "document:tenant-a:doc-42")// -> Ok(["tenant-a", "doc-42"])pub fn extract_wildcards( TopicPattern, String) -> Result(List(String), ExtractError)from_segments
Section titled “from_segments”Build a topic from segments
Examples
Section titled “Examples”from_segments(["room", "lobby"]) // -> "room:lobby"from_segments(["doc", "tenant", "123"]) // -> "doc:tenant:123"pub fn from_segments(List(String)) -> Stringmatches
Section titled “matches”Check if a topic matches a pattern
Examples
Section titled “Examples”matches(Wildcard("room:"), "room:lobby") // -> Truematches(Wildcard("room:"), "user:123") // -> Falsematches(Exact("room:lobby"), "room:lobby") // -> Truematches(Exact("room:lobby"), "room:other") // -> Falsematches(parse_pattern("document:*:ops"), "document:tenant-a:ops") // -> Truematches(parse_pattern("document:*:ops"), "document:tenant-a:view") // -> Falsepub fn matches( TopicPattern, String) -> Boolnamespace
Section titled “namespace”Get the first segment (namespace) of a topic
Examples
Section titled “Examples”namespace("room:lobby") // -> Ok("room")namespace("") // -> Error(EmptyNamespace)pub fn namespace(String) -> Result(String, ExtractError)parse_pattern
Section titled “parse_pattern”Parse a pattern string into TopicPattern
Examples
Section titled “Examples”parse_pattern("room:*") // -> Wildcard("room:")parse_pattern("room:lobby") // -> Exact("room:lobby")parse_pattern("document:*:ops") // -> SegmentWildcard(["document", "*", "ops"])parse_pattern("document:*:*") // -> SegmentWildcard(["document", "*", "*"])parse_pattern("document:tenant-a:*") // -> Wildcard("document:tenant-a:")pub fn parse_pattern(String) -> TopicPatternsegments
Section titled “segments”Parse a topic into segments by splitting on ":"
Examples
Section titled “Examples”segments("room:lobby") // -> ["room", "lobby"]segments("doc:tenant:123:ops") // -> ["doc", "tenant", "123", "ops"]pub fn segments(String) -> List(String)validate
Section titled “validate”Validate a topic string
Topics must:
- Not be empty
- Not contain control characters (codepoints 0–31 or 127)
- Not start or end with ":"
pub fn validate(String) -> Result(String, TopicError)validate_event
Section titled “validate_event”Validate an event name string
Event names must:
- Not be empty
- Not contain control characters (codepoints 0–31 or 127)
pub fn validate_event(String) -> Result(String, TopicError)validate_pattern
Section titled “validate_pattern”Validate a topic pattern string
Patterns must:
- Not be empty
- Not contain control characters (codepoints 0–31 or 127)
The bare pattern "*" is valid: it parses to a catch-all wildcard that
matches every topic.
pub fn validate_pattern(String) -> Result(String, TopicError)