Repository navigation
Releases: TeamMilestone/tsip_parser_gem
Release list
v0.2.3 — Address.new 0-arg allocator
Gem-only release per docs/V0_2_3_HANDOFF.md. No crate change — tsip-parser = \"0.2\" unchanged.
What changed
Previously TsipParser::Address.new raised TypeError: allocator undefined for TsipParser::Address because the magnus::wrap macro does not register a Ruby allocator. This release registers a 0-arg new singleton method that returns an empty Address (display_name: nil, uri: nil, params: {}), then the existing Ruby-side setters assemble it:
a = TsipParser::Address.new
a.display_name = \"Alice\"
a.uri = TsipParser::Uri.parse(\"sip:alice@example.com\")
a.params[\"tag\"] = \"xyz\"
a.to_s # => \"\\\"Alice\\\" <sip:alice@example.com>;tag=xyz\"Unblocks the tsip-core bridge Address.build helper to drop its placeholder-parse workaround (parse(\"<sip:_@_>\")), which at 8k cps dialog throughput costs ~16k unnecessary parses/s.
Tests
41 runs / 72 assertions / 0 failures — 39 existing + 2 new.
Install
gem install tsip_parserRubyGems: https://rubygems.org/gems/tsip_parser/versions/0.2.3
v0.2.2 — tsip-core class-alias surface
Gem-only release per docs/V0_2_2_HANDOFF.md. No crate change — tsip-parser = \"0.2\" still resolves to 0.2.1.
What changed
Exposes three crate class methods that tsip-core needs to replace its per-parse bridge shim with a direct TsipCore::Sip::Uri = TsipParser::Uri class alias. Closes the −2.8% throughput regression measured in the tsip-core integration bench on 2026-04-19.
TsipParser::Uri.parse_range(str, from, to)— byte-range parse.tsip-core'sAddress.parseuses this to parse the URI inside<...>without substring alloc. Offsets are validated + must land on UTF-8 char boundaries; raisesParseErrorotherwise.TsipParser::Uri.parse_param(raw, hash)— writes onekey[=value]segment into an existing Ruby Hash. Used by tsip-coreVia.parseon each semicolon-split segment. Key-only segments insert\"\"; empty raw is a no-op; duplicate keys overwrite.TsipParser::Uri.parse_host_port(str)— returns[host, port_or_nil]. IPv6 bracket form ([::1]:5060) supported.
Not added (per HANDOFF §3.3)
Address.new(display_name:, uri:, params:) kwargs constructor. tsip-core is adding an Address.build(...) helper on its side instead.
Tests
39 runs / 67 assertions / 0 failures — 25 existing + 14 new class-method tests.
Install
gem install tsip_parserRubyGems: https://rubygems.org/gems/tsip_parser/versions/0.2.2
v0.2.1 — Escape parity with crate Display
Tracks upstream tsip-parser 0.2.1.
What changed
Accepts URI-level param keys/values containing ; ? & = < >. Round-trip stability comes from render-side pct-escape (lowercase hex). Closes the last xoracle parity case (sip:alice@host;<evil>=1) vs the Ruby tsip-core reference.
Gem-side fix (behavioral)
Previously the Ruby serialization path — triggered once params or headers was touched — wrote fields literally, diverging from the Rust Display for inputs with @ : ; ? < > % & = or whitespace. Now Uri#append_to mirrors the crate's escape set so fast-path and slow-path produce identical output.
Performance
M1 macOS, Ruby 4.0.1, release build:
| endpoint | tsip_parser | tsip-core | speedup |
|---|---|---|---|
Uri.parse |
646k ips | 41k ips | 15.8× |
Address.parse |
694k ips | 41k ips | 16.8× |
Escape runs only on the mutation-touched slow path, so parse throughput is unchanged from 0.2.0.
Upgrade notes
Drop-in. If you had rescue TsipParser::ParseError catching inputs with > in params, those now parse — audit and simplify.
Install
gem install tsip_parserRubyGems: https://rubygems.org/gems/tsip_parser/versions/0.2.1
v0.2.0 — Track crate 0.2.0
Tracks upstream tsip-parser 0.2.0.
What changed
Behavior, not API. The Ruby surface (TsipParser::Uri, ::Address, ParseError, helper methods) is identical to 0.1.0. What moved is the accepted-input set:
- Accepts pct-encoded userinfo specials.
- Accepts
<in param keys. - Accepts leading/trailing whitespace in URI-level param/header values.
- Round-trip stability is preserved via render-side pct-escape — pct-decoded fields (userinfo, URI header key/value) are pct-escaped when
to_sserializes.
Narrow parse-time rejections still remain for bytes that literal param storage cannot round-trip: > in any param, ? in URI-level params.
Performance
M1 macOS, Ruby 4.0.1, release build:
| endpoint | tsip_parser | tsip-core | speedup |
|---|---|---|---|
Uri.parse |
654k ips | 41k ips | 16.1× |
Address.parse |
695k ips | 41k ips | 16.8× |
Slightly faster than 0.1.0 (permissive parse skips validation work).
Upgrade notes
Drop-in. If your code depended on InvalidHost being raised for previously-rejected inputs, those will now parse — audit any call sites that did rescue TsipParser::ParseError expecting that specific behavior.
Install
gem install tsip_parserRubyGems: https://rubygems.org/gems/tsip_parser/versions/0.2.0
v0.1.0 — Initial release
First published release. Thin Ruby binding over the tsip-parser Rust crate (pinned to ~> 0.1, resolves to 0.1.1).
Features
TsipParser::Uri.parse(str)— RFC 3261 §19.1 SIP / SIPS / tel URI parserTsipParser::Address.parse(str)— RFC 3261 §25.1 name-addr / addr-specTsipParser::ParseError(subclass ofArgumentError) — tsip-core-compatible error pathUri.parse_many/Address.parse_many— batch FFIuri.param(k)/uri.header(k)/address.param(k)— direct Vec lookup, no Hash materialization- Params / headers memoized on the Ruby side so
uri.params["t"] = "tls"round-trips throughto_scorrectly
Performance
M1 macOS, Ruby 4.0.1, release build:
| endpoint | tsip_parser | tsip-core | speedup |
|---|---|---|---|
Uri.parse |
595k ips | 40k ips | 14.8× |
Address.parse |
672k ips | 41k ips | 16.6× |
Clears the 10× target from the project's HANDOVER doc.
Install
gem install tsip_parserRubyGems: https://rubygems.org/gems/tsip_parser/versions/0.1.0