aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/world/net/uri/encoding.lux
blob: 5c84a2aa889559cb385ace6492cf6304ba16950c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
... This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
... If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

... https://en.wikipedia.org/wiki/Percent-encoding
(.require
 [library
  [lux (.except)
   [abstract
    [monad (.only do)]]
   [control
    ["[0]" try (.only Try)]
    ["[0]" exception (.only Exception)]]
   [data
    ["[0]" text (.only)
     [char (.only Char)]]
    [collection
     ["[0]" set (.only Set)]]]
   [math
    [number
     ["[0]" nat]]]]])

(type .public URI_Encoded
  Text)

(with_expansions [<reserved> (these [" " "%20"]
                                    ["!" "%21"]
                                    ["#" "%23"]
                                    ["$" "%24"]
                                    ["%" "%25"]
                                    ["&" "%26"]
                                    ["'" "%27"]
                                    ["(" "%28"]
                                    [")" "%29"]
                                    ["*" "%2A"]
                                    ["+" "%2B"]
                                    ["," "%2C"]
                                    ["/" "%2F"]
                                    [":" "%3A"]
                                    [";" "%3B"]
                                    ["=" "%3D"]
                                    ["?" "%3F"]
                                    ["@" "%40"]
                                    ["[" "%5B"]
                                    ["]" "%5D"])]
  (def .public reserved
    (Set Char)
    (set.of_list nat.hash
                 (`` (list (,, (with_template [<char> <encoding>]
                                 [(char <char>)]
                                 
                                 <reserved>))))))
  
  (def .public (encoded input)
    (-> Text URI_Encoded)
    (let [size (text.size input)]
      (loop (again [index 0
                    slice_start 0
                    output ""])
        (if (nat.< size index)
          (`` (when (.text_char# index input)
                (,, (with_template [<char> <encoding>]
                      [(char <char>)
                       (let [index' (++ index)]
                         (again index'
                                index'
                                (.text_composite# output
                                                  (.text_clip# slice_start (nat.- slice_start index) input)
                                                  <encoding>)))]

                      <reserved>))
                
                _
                (again (++ index)
                       slice_start
                       output)))
          (.text_composite# output
                            (.text_clip# slice_start (nat.- slice_start index) input))))))
  )

(def escape
  (char "%"))

(exception.def (invalid it)
  (Exception URI_Encoded)
  (exception.report
   (list ["Value" (text.format it)])))

(def .public (decoded input)
  (-> URI_Encoded (Try Text))
  (let [size (text.size input)]
    (loop (again [index 0
                  slice_start 0
                  output ""])
      (if (nat.< size index)
        (`` (when (.text_char# index input)
              ..escape
              (let [encoding_start (++ index)
                    encoding_end (++ encoding_start)]
                (if (nat.< size encoding_end)
                  (do try.monad
                    [value (|> input
                               (.text_clip# encoding_start 2)
                               (of nat.hex decoded))
                     .let [index' (++ encoding_end)]]
                    (again index'
                           index'
                           (.text_composite# output
                                             (.text_clip# slice_start (nat.- slice_start index) input)
                                             (text.of_char value))))
                  (exception.except ..invalid [input])))
              
              _
              (again (++ index)
                     slice_start
                     output)))
        {try.#Success (|> input
                          (.text_clip# slice_start (nat.- slice_start index))
                          (.text_composite# output))}))))