# `VerifiedPubSub.Topic`
[🔗](https://github.com/CuriousCurmudgeon/verified_pubsub/blob/v0.1.0/lib/verified_pubsub/topic.ex#L1)

Builds the segment of a wire topic that a param fills.

A manifest declares a topic as a list of segments, and `:` joins the segments. A string
is a literal, and an atom is a param.

## Why each call checks the param value

When three properties hold, an interpolated topic is always the topic that its call site
names:

  1. Each param fills a whole segment. The list shape gives this property: a param is
     its own element, and a literal cannot contain the separator.
  2. No two declared topics can match the same wire topic. The manifest checks this
     property when it compiles.
  3. A param value is not empty and does not contain the separator. This module checks
     this property on each call.

Each property is necessary. `["a", :x]` and `["a", :x, "b"]` have different segment
counts, so (2) holds. But `x = "1:b"` on the first topic builds `"a:1:b"`, and the second
topic builds the same wire topic from `x = "1"`. Without (3), a broadcast reaches the
subscribers of the other topic.

# `pattern`

```elixir
@spec pattern([VerifiedPubSub.Dsl.Topic.segment()]) :: String.t()
```

Renders segments as a wire pattern, with each param in angle brackets.

    iex> VerifiedPubSub.Topic.pattern(["owners", :owner_id, "pets"])
    "owners:<owner_id>:pets"

Errors show a topic in this form. A reader with a wire topic from a log can then find the
declared topic that it belongs to.

# `segment!`

```elixir
@spec segment!(module(), atom(), atom(), term()) :: String.t()
```

Converts `value` to a string, and checks that it can fill one segment of the topic.

Raises `VerifiedPubSub.TopicError` when it cannot.

# `separator`

```elixir
@spec separator() :: String.t()
```

The character that separates topic segments.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
