Browse Source

forgot to include this, required for minitel

master
XeonSquared 5 months ago
parent
commit
735a8f5ee2
1 changed files with 145 additions and 0 deletions
  1. 145
    0
      lib/serialization.lua

+ 145
- 0
lib/serialization.lua View File

@@ -0,0 +1,145 @@
1
+-- serialization lib borrowed from OpenOS
2
+local serialization = {}
3
+
4
+-- delay loaded tables fail to deserialize cross [C] boundaries (such as when having to read files that cause yields)
5
+local local_pairs = function(tbl)
6
+  local mt = getmetatable(tbl)
7
+  return (mt and mt.__pairs or pairs)(tbl)
8
+end
9
+
10
+-- Important: pretty formatting will allow presenting non-serializable values
11
+-- but may generate output that cannot be unserialized back.
12
+function serialization.serialize(value, pretty)
13
+  local kw =  {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true,
14
+               ["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true,
15
+               ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true,
16
+               ["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true,
17
+               ["repeat"]=true, ["return"]=true, ["then"]=true, ["true"]=true,
18
+               ["until"]=true, ["while"]=true}
19
+  local id = "^[%a_][%w_]*$"
20
+  local ts = {}
21
+  local result_pack = {}
22
+  local function recurse(current_value, depth)
23
+    local t = type(current_value)
24
+    if t == "number" then
25
+      if current_value ~= current_value then
26
+        table.insert(result_pack, "0/0")
27
+      elseif current_value == math.huge then
28
+        table.insert(result_pack, "math.huge")
29
+      elseif current_value == -math.huge then
30
+        table.insert(result_pack, "-math.huge")
31
+      else
32
+        table.insert(result_pack, tostring(current_value))
33
+      end
34
+    elseif t == "string" then
35
+      table.insert(result_pack, (string.format("%q", current_value):gsub("\\\n","\\n")))
36
+    elseif
37
+      t == "nil" or
38
+      t == "boolean" or
39
+      pretty and (t ~= "table" or (getmetatable(current_value) or {}).__tostring) then
40
+      table.insert(result_pack, tostring(current_value))
41
+    elseif t == "table" then
42
+      if ts[current_value] then
43
+        if pretty then
44
+          table.insert(result_pack, "recursion")
45
+          return
46
+        else
47
+          error("tables with cycles are not supported")
48
+        end
49
+      end
50
+      ts[current_value] = true
51
+      local f
52
+      if pretty then
53
+        local ks, sks, oks = {}, {}, {}
54
+        for k in local_pairs(current_value) do
55
+          if type(k) == "number" then
56
+            table.insert(ks, k)
57
+          elseif type(k) == "string" then
58
+            table.insert(sks, k)
59
+          else
60
+            table.insert(oks, k)
61
+          end
62
+        end
63
+        table.sort(ks)
64
+        table.sort(sks)
65
+        for _, k in ipairs(sks) do
66
+          table.insert(ks, k)
67
+        end
68
+        for _, k in ipairs(oks) do
69
+          table.insert(ks, k)
70
+        end
71
+        local n = 0
72
+        f = table.pack(function()
73
+          n = n + 1
74
+          local k = ks[n]
75
+          if k ~= nil then
76
+            return k, current_value[k]
77
+          else
78
+            return nil
79
+          end
80
+        end)
81
+      else
82
+        f = table.pack(local_pairs(current_value))
83
+      end
84
+      local i = 1
85
+      local first = true
86
+      table.insert(result_pack, "{")
87
+      for k, v in table.unpack(f) do
88
+        if not first then
89
+          table.insert(result_pack, ",")
90
+          if pretty then
91
+            table.insert(result_pack, "\n" .. string.rep(" ", depth))
92
+          end
93
+        end
94
+        first = nil
95
+        local tk = type(k)
96
+        if tk == "number" and k == i then
97
+          i = i + 1
98
+          recurse(v, depth + 1)
99
+        else
100
+          if tk == "string" and not kw[k] and string.match(k, id) then
101
+            table.insert(result_pack, k)
102
+          else
103
+            table.insert(result_pack, "[")
104
+            recurse(k, depth + 1)
105
+            table.insert(result_pack, "]")
106
+          end
107
+          table.insert(result_pack, "=")
108
+          recurse(v, depth + 1)
109
+        end
110
+      end
111
+      ts[current_value] = nil -- allow writing same table more than once
112
+      table.insert(result_pack, "}")
113
+    else
114
+      error("unsupported type: " .. t)
115
+    end
116
+  end
117
+  recurse(value, 1)
118
+  local result = table.concat(result_pack)
119
+  if pretty then
120
+    local limit = type(pretty) == "number" and pretty or 10
121
+    local truncate = 0
122
+    while limit > 0 and truncate do
123
+      truncate = string.find(result, "\n", truncate + 1, true)
124
+      limit = limit - 1
125
+    end
126
+    if truncate then
127
+      return result:sub(1, truncate) .. "..."
128
+    end
129
+  end
130
+  return result
131
+end
132
+
133
+function serialization.unserialize(data)
134
+  local result, reason = load("return " .. data, "=data", nil, {math={huge=math.huge}})
135
+  if not result then
136
+    return nil, reason
137
+  end
138
+  local ok, output = pcall(result)
139
+  if not ok then
140
+    return nil, output
141
+  end
142
+  return output
143
+end
144
+
145
+return serialization

Loading…
Cancel
Save