std.uri.Values
type pub inline ValuesA mapping of URI/percent-encoded key-value pairs.
RFC 3986 doesn't specify how exactly a URI encoded/query string should be
interpreted. This type separates pairs using a & and separates the key and
value using a =. The characters &, =, ? and # (along with multi-byte
characters) are percent-encoded when found in a key or value.
Duplicate pairs are allowed, meaning the query string ?key=10&key=20 results
in a mapping containing two values for key.
While the keys of each pair are a String and thus must be valid UTF-8, the
values are ByteArray values, allowing for arbitrary bytes (after percent
decoding) as the values.
The order of key-value pairs is the same as the order in which they are
inserted, similar to std.map.Map.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('age', '42')
map.add('name', 'Bob')
map.add('age', '50')
map.to_string # => 'name=Alice&age=42&name=Bob&age=50'
Static methods
new
Show source codeHide source code
fn pub static new -> Values {
Values(Map.new)
}fn pub static new -> ValuesReturns an empty Values.
Examples
import std.uri (Values)
Values.new.size # => 0
parse
Show source codeHide source code
fn pub static parse[B: Bytes](input: ref B) -> Option[Values] {
let map = Values.new
for chunk in Slice.new(input, 0, input.size).split('&') {
if chunk.empty? { next }
match chunk.split_once('=') {
case Some((lhs, rhs)) -> {
let key = try parse_query(lhs)
let val = try parse_query(rhs)
map.add(key.into_string, val)
}
case _ -> {
let key = try parse_query(chunk)
map.add(key.into_string, ByteArray.new)
}
}
}
Option.Some(map)
}fn pub static parse[B: Bytes](input: ref B) -> Option[Values]Parses and decodes a URI encoded set of key-value pairs.
If the input is invalid (e.g. it contains invalid percent-encoded
sequences), an Option.None is returned.
RFC 3986 doesn't specify how exactly a query string should be interpreted.
This method follows the widely adopted approach of splitting pairs on a &
and splitting keys and values on the first =.
Duplicate pairs are allowed, meaning ?key=10&key=20 yields the pairs
('key', 10) and ('key', 20).
Examples
import std.uri (Values)
let map = Values.parse('name=Alice&age=42').get
map.string('name') # => Result.Ok('Alice')
map.string('age') # => Result.Ok('42')
Instance methods
!=
Show source codeHide source code
fn pub !=(other: ref Self) -> Bool {
!(self == other)
}fn pub !=(other: ref Self) -> BoolReturns true if self and the given object are not equal to each other.
==
Show source codeHide source code
fn pub ==(other: ref Values) -> Bool {
@map == other.map
}fn pub ==(other: ref Values) -> BoolReturns true if self and the given object are equal to each other.
This operator is used to perform structural equality. This means two objects residing in different memory locations may be considered equal, provided their structure is equal. For example, two different arrays may be considered to have structural equality if they contain the exact same values.
add
Show source codeHide source code
fn pub mut add[B: Bytes](name: String, value: ref B) {
let value = value.to_byte_array
match @map.try_set(name, QueryValue.Single(value)) {
case Error((name, Single(_), Single(new))) -> {
let ex = match @map.remove(name) {
case Ok(Single(v)) -> v
case _ -> panic('unreachable')
}
@map.set(name, QueryValue.Multiple([ex, new]))
}
case Error((_, Multiple(ex), Single(new))) -> ex.push(new)
case _ -> {}
}
}fn pub mut add[B: Bytes](name: String, value: ref B)Adds a key-value pair to self.
If the key is already present, the value is added to the list instead of overwriting the previous value.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
clear
Show source codeHide source code
fn pub mut clear {
@map.clear
}fn pub mut clearRemoves all key-value pairs in self.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
map.clear
map.size # => 0
clone
Show source codeHide source code
fn pub clone -> Self {
Self(@map.clone)
}fn pub clone -> ValuesCreates a clone of self.
The returned value is an owned value that is the same type as the receiver
of this method. For example, cloning a ref Array[Int] results in a
Array[Int], not another ref Array[Int].
encode
Show source codeHide source code
fn pub encode(into: mut ByteArray) {
let mut pairs = 0
for (key, val) in @map.iter {
match val {
case Single(v) -> {
if pairs > 0 { into.push(AMP) }
encode_query_pair_into(key, v, into)
pairs += 1
}
case Multiple(vals) -> {
for val in vals.iter {
if pairs > 0 { into.push(AMP) }
encode_query_pair_into(key, val, into)
pairs += 1
}
}
}
}
}fn pub encode(into: mut ByteArray)Encodes self as a sequence of bytes into the given ByteArray.
After encoding the data it can be safely used in a query string component or
as the body for an application/x-www-form-urlencoded encoded form.
If you just want a String instead of writing the data to an existing
ByteArray, use Values.to_string instead.
Examples
import std.uri (Values)
let buf = ByteArray.new
let map = Values.new
map.add('foo bar', 'value')
map.add('key#?&=', 'value#?&=')
map.encode(buf)
buf.to_string # => 'foo%20bar=value&key%23?%26%3D=value%23?%26%3D'
fmt
Show source codeHide source code
fn pub fmt(formatter: mut Formatter) {
formatter.object('Values').field('map', @map).finish
}fn pub fmt(formatter: mut Formatter)Formats self in a human-readable format for debugging purposes.
get
Show source codeHide source code
fn pub get(name: String) -> Result[ref ByteArray, MissingKey[String]] {
match value(name) {
case Ok(Single(v)) -> Result.Ok(v)
case Ok(Multiple(v)) -> Result.Ok(v.get(0).or_panic)
case _ -> Result.Error(MissingKey.new(name))
}
}fn pub get(name: String) -> Result[ref ByteArray, MissingKey[String]]Returns the first value of the given key.
If the key is missing, a MissingKey error is returned.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.get('name').map(fn (v) { v.to_string }) # => Result.Ok('Alice')
map.get('age') # => Result.Error(MissingKey(...))
get_all
Show source codeHide source code
fn pub get_all(name: String) -> Stream[ref ByteArray] {
match @map.get(name) {
case Ok(Single(v)) -> {
let mut done = false
Stream.new(fn move {
if done := true { Option.None } else { Option.Some(v) }
})
}
case Ok(Multiple(v)) -> v.iter
case _ -> Stream.new(fn move { Option.None })
}
}fn pub get_all(name: String) -> Stream[ref ByteArray]Returns an iterator over all the values of the given key.
If the key isn't assigned any values, the returned iterator yields no values.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
let iter = map.get_all('name')
iter.next.map(fn (v) { v.to_string }) # => Option.Some('Alice')
iter.next.map(fn (v) { v.to_string }) # => Option.Some('Bob')
keys
Show source codeHide source code
fn pub keys -> Stream[String] {
@map.keys
}fn pub keys -> Stream[String]Returns an iterator over the parameter names.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
let iter = map.keys
iter.next # => Option.Some(('name'))
iter.next # => Option.None
remove
Show source codeHide source code
fn pub mut remove[B: Bytes](name: String, value: ref B) {
let rm = match @map.get_mut(name) {
case Ok(Single(v)) -> v.equals?(value)
case Ok(Multiple(v)) -> {
v.remove_if(fn (v) { v.equals?(value) })
v.empty?
}
case _ -> false
}
if rm { @map.remove(name) }
}fn pub mut remove[B: Bytes](name: String, value: ref B)Removes all key-value pairs that match the given key and value.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
map.remove('name', 'Alice')
map.get('name').map(fn (v) { v.to_string }) # => Result.Ok('Bob')
remove_all
Show source codeHide source code
fn pub mut remove_all(name: String) {
@map.remove(name)
}fn pub mut remove_all(name: String)Removes all values of the key name.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.add('name', 'Bob')
map.remove_all('name')
map.get('name') # => Result.Error(MissingKey(...))
map.size # => 0
size
Show source codeHide source code
fn pub inline size -> Int {
@map.size
}fn pub inline size -> IntReturns the number of key-value pairs in self.
Examples
import std.uri (Values)
let map = Values.new
map.size # => 0
map.add('name', 'Alice')
map.size # => 1
string
Show source codeHide source code
fn pub string(name: String) -> Result[String, MissingKey[String]] {
match get(name) {
case Ok(v) -> Result.Ok(v.to_string)
case Error(e) -> Result.Error(e)
}
}fn pub string(name: String) -> Result[String, MissingKey[String]]Returns the first value of the given key, returning it as a String.
By far the most common case when working with URI encoded key-value pairs is
to retrieve a single value as a String. Using this method you don't need
to manually map the Result[ref ByteArray, ...] from Values.get to a
Result[String, ...].
Refer to the documentation of Values.get for more details.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.string('name') # => Result.Ok('Alice')
map.string('age') # => Result.Error(MissingKey(...))
to_query
Show source codeHide source code
fn pub to_query -> Query {
Query(to_string)
}fn pub to_query -> QueryReturns a Query containing the percent-encoded key-value pairs.
Examples
import std.uri (Uri, Values)
let uri = Uri.new
let map = Values.new
map.add('name', 'Alice')
uri.query = map.to_query
uri.to_string # => '?name=Alice'
to_string
Show source codeHide source code
fn pub to_string -> String {
let buf = ByteArray.new
encode(buf)
buf.into_string
}fn pub to_string -> StringReturns a String containing the (optionally percent-encoded) key-value
pairs as a URI compatible String.
value
Show source codeHide source code
fn pub value(name: String) -> Result[ref QueryValue, MissingKey[String]] {
@map.get(name)
}fn pub value(name: String) -> Result[ref QueryValue, MissingKey[String]]Returns the raw value of the given key.
If the key is missing, a MissingKey error is returned.
Examples
import std.uri (Values)
let map = Values.new
map.add('name', 'Alice')
map.value('name') # => Result.Ok(QueryValue.Single(...))
Implemented traits
Clone
impl Clone for ValuesEqual
impl Equal for ValuesFormat
impl Format for ValuesToString
impl ToString for Values