summaryrefslogtreecommitdiff
path: root/src/serializing.lisp
blob: e9c46f6cd000594e775d03ac2150d1a514bc307a (plain) (blame)
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
;; SPDX-License-Identifier: EUPL-1.2
;; SPDX-FileCopyrightText: 2025 Uko Kokņevičs <perkontevs@gmail.com>
(defpackage :ukkoclot/src/serializing
  (:use :c2cl :iterate)
  (:import-from :log)
  (:import-from :str)
  (:local-nicknames
   (:jzon :com.inuoe.jzon))
  (:export :fixup-args :fixup-value :parse-value :try-parse-value))
(in-package :ukkoclot/src/serializing)

(defun fixup-args (args)
  (iter (for (key . value) in args)
        (collect (cons (str:snake-case key) (fixup-value value)))))

(defgeneric fixup-value (value)
  (:documentation "Fixup outgoing *top-level* `value' before passing it to telegram.")
  (:method (value)
    (jzon:stringify value :pretty *print-pretty*))
  (:method ((value null))
    value)
  (:method ((value number))
    value)
  (:method ((value pathname))
    value)
  (:method ((value string))
    value))

(defgeneric parse-value (type json)
  (:documentation "Parse incoming value of `type' from the parsed `json'.")
  (:method (type json)
    (log:error "I don't know how to parse simple type ~A!" type)
    (error "I don't know how to parse simple type ~A!" type))
  (:method ((type (eql 'boolean)) json)
    (check-type json boolean)
    json)
  (:method ((type (eql 'integer)) json)
    (check-type json integer)
    json)
  (:method ((type (eql 'null)) json)
    (check-type json null)
    json)
  (:method ((type (eql 'string)) json)
    (check-type json string)
    json))

(defmethod parse-value ((type cons) json)
  (cond ((and (eq (first type) 'array)
              (null (cddr type)))
         (when json
           (let ((element-type (cadr type)))
             (iter (for element in-vector json)
               (collect (parse-value element-type element) result-type vector)))))
        ((eq (first type) 'or)
         (iter (for el-type in (rest type))
           (multiple-value-bind (success res) (try-parse-value el-type json)
             (when success
               (return res)))
           (finally
            (error "Failed to parse ~S as ~A!" json type))))
        (t
         (error "I don't know how to parse complex type ~A!" type))))

(defun try-parse-value (type json)
  (handler-case (values t (parse-value type json))
    (error () (values nil nil))))