| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of The BSD 3-Clause License
- // that can be found in the LICENSE file.
- package uritemplate
- import "strings"
- // A varname containing pct-encoded characters is not the same variable as
- // a varname with those same characters decoded.
- //
- // -- https://tools.ietf.org/html/rfc6570#section-2.3
- type Values map[string]Value
- func (v Values) Set(name string, value Value) {
- v[name] = value
- }
- func (v Values) Get(name string) Value {
- if v == nil {
- return Value{}
- }
- return v[name]
- }
- type ValueType uint8
- const (
- ValueTypeString = iota
- ValueTypeList
- ValueTypeKV
- valueTypeLast
- )
- var valueTypeNames = []string{
- "String",
- "List",
- "KV",
- }
- func (vt ValueType) String() string {
- if vt < valueTypeLast {
- return valueTypeNames[vt]
- }
- return ""
- }
- type Value struct {
- T ValueType
- V []string
- }
- func (v Value) String() string {
- if v.Valid() && v.T == ValueTypeString {
- return v.V[0]
- }
- return ""
- }
- func (v Value) List() []string {
- if v.Valid() && v.T == ValueTypeList {
- return v.V
- }
- return nil
- }
- func (v Value) KV() []string {
- if v.Valid() && v.T == ValueTypeKV {
- return v.V
- }
- return nil
- }
- func (v Value) Valid() bool {
- switch v.T {
- default:
- return false
- case ValueTypeString:
- return len(v.V) > 0
- case ValueTypeList:
- return len(v.V) > 0
- case ValueTypeKV:
- return len(v.V) > 0 && len(v.V)%2 == 0
- }
- }
- func (v Value) expand(w *strings.Builder, spec varspec, exp *expression) error {
- switch v.T {
- case ValueTypeString:
- val := v.V[0]
- var maxlen int
- if max := len(val); spec.maxlen < 1 || spec.maxlen > max {
- maxlen = max
- } else {
- maxlen = spec.maxlen
- }
- if exp.named {
- w.WriteString(spec.name)
- if val == "" {
- w.WriteString(exp.ifemp)
- return nil
- }
- w.WriteByte('=')
- }
- return exp.escape(w, val[:maxlen])
- case ValueTypeList:
- var sep string
- if spec.explode {
- sep = exp.sep
- } else {
- sep = ","
- }
- var pre string
- var preifemp string
- if spec.explode && exp.named {
- pre = spec.name + "="
- preifemp = spec.name + exp.ifemp
- }
- if !spec.explode && exp.named {
- w.WriteString(spec.name)
- w.WriteByte('=')
- }
- for i := range v.V {
- val := v.V[i]
- if i > 0 {
- w.WriteString(sep)
- }
- if val == "" {
- w.WriteString(preifemp)
- continue
- }
- w.WriteString(pre)
- if err := exp.escape(w, val); err != nil {
- return err
- }
- }
- case ValueTypeKV:
- var sep string
- var kvsep string
- if spec.explode {
- sep = exp.sep
- kvsep = "="
- } else {
- sep = ","
- kvsep = ","
- }
- var ifemp string
- var kescape escapeFunc
- if spec.explode && exp.named {
- ifemp = exp.ifemp
- kescape = escapeLiteral
- } else {
- ifemp = ","
- kescape = exp.escape
- }
- if !spec.explode && exp.named {
- w.WriteString(spec.name)
- w.WriteByte('=')
- }
- for i := 0; i < len(v.V); i += 2 {
- if i > 0 {
- w.WriteString(sep)
- }
- if err := kescape(w, v.V[i]); err != nil {
- return err
- }
- if v.V[i+1] == "" {
- w.WriteString(ifemp)
- continue
- }
- w.WriteString(kvsep)
- if err := exp.escape(w, v.V[i+1]); err != nil {
- return err
- }
- }
- }
- return nil
- }
- // String returns Value that represents string.
- func String(v string) Value {
- return Value{
- T: ValueTypeString,
- V: []string{v},
- }
- }
- // List returns Value that represents list.
- func List(v ...string) Value {
- return Value{
- T: ValueTypeList,
- V: v,
- }
- }
- // KV returns Value that represents associative list.
- // KV panics if len(kv) is not even.
- func KV(kv ...string) Value {
- if len(kv)%2 != 0 {
- panic("uritemplate.go: count of the kv must be even number")
- }
- return Value{
- T: ValueTypeKV,
- V: kv,
- }
- }
|