Skip to content

Commit 6fa1e92

Browse files
committed
xml: make structs serializable, but enforce contracts
Related to: racket/scribble#498 Related to: racket#5282
1 parent bf08ef2 commit 6fa1e92

File tree

2 files changed

+93
-18
lines changed

2 files changed

+93
-18
lines changed

racket/collects/xml/private/core.rkt

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,90 @@
11
#lang racket/base
2-
(require racket/contract/base)
2+
(require racket/runtime-path
3+
(for-syntax racket/base))
34

45
;; Core structures needed for `xml/xexpr'
56

6-
(provide (all-defined-out))
7+
(provide permissive-xexprs
8+
(struct-out source)
9+
(struct-out comment)
10+
(struct-out p-i)
11+
(struct-out pcdata)
12+
(struct-out cdata)
13+
valid-char?)
714

815
; permissive-xexprs : parameter bool
916
(define permissive-xexprs (make-parameter #f))
1017

18+
; support for serialization with contracts enforced on deserialization
19+
(module serialization-support racket/base
20+
(require racket/serialize-structs
21+
(for-syntax racket/syntax
22+
racket/struct-info
23+
racket/base))
24+
(define ((cycles-not-allowed name))
25+
(error name "invalid serialization;\n cycles not allowed"))
26+
(define-for-syntax ((make-define-serializable-struct deserialize-info-mpi
27+
get-checked-constructor)
28+
stx)
29+
(syntax-case stx ()
30+
[(_ name-maybe-super (fld ...))
31+
(with-syntax* ([(name super-fld-ref ...)
32+
(syntax-case #'name-maybe-super ()
33+
[name
34+
(identifier? #'name)
35+
#'(name)]
36+
[(name super)
37+
#`(name
38+
#,@(reverse (list-ref (extract-struct-info (syntax-local-value #'super))
39+
3)))])]
40+
[(name-fld-ref ...)
41+
(for/list ([id (in-list (syntax->list #'(fld ...)))])
42+
(format-id id "~a-~a" #'name id))]
43+
[deserialize-info:name-v0
44+
(format-id #'name "deserialize-info:~a-v0" #'name)])
45+
#`(begin
46+
(define-struct name-maybe-super (fld ...)
47+
#:property prop:serializable
48+
(make-serialize-info (λ (this)
49+
(vector (super-fld-ref this) ...
50+
(name-fld-ref this) ...))
51+
(cons 'deserialize-info:name-v0 #,deserialize-info-mpi)
52+
#f
53+
(or (current-load-relative-directory) (current-directory)))
54+
#:transparent)
55+
(module+ deserialize-info
56+
(provide deserialize-info:name-v0)
57+
(define deserialize-info:name-v0
58+
(make-deserialize-info (#,get-checked-constructor name)
59+
(cycles-not-allowed 'name))))))]))
60+
(provide (for-syntax make-define-serializable-struct)))
61+
(require 'serialization-support)
62+
(define-runtime-module-path-index deserialize-info-mpi '(submod "." deserialize-info))
63+
(module+ deserialize-info
64+
(define-runtime-module-path-index mpi-for-contracts "structures.rkt")
65+
(define-syntax-rule (get-checked-constructor name)
66+
(dynamic-require mpi-for-contracts 'name)))
67+
(define-syntax define-xexpr-struct
68+
(make-define-serializable-struct #'deserialize-info-mpi #'get-checked-constructor))
69+
1170
; Source = (make-source Location Location)
12-
(define-struct source (start stop) #:transparent)
71+
(define-struct source (start stop)
72+
; NOT define-xexpr-struct (and not serializable) because this is used as an abstract base type:
73+
; if a subtype is not intended to be serializable, it shouldn't be serialized by inheritance
74+
#:transparent)
1375

1476
; Comment = (make-comment String)
15-
(define-struct comment (text) #:transparent)
77+
(define-xexpr-struct comment (text))
1678

1779
; Processing-instruction = (make-p-i Location Location String String)
1880
; also represents XMLDecl
19-
(define-struct (p-i source) (target-name instruction) #:transparent)
81+
(define-xexpr-struct (p-i source) (target-name instruction))
2082

2183
; Pcdata = (make-pcdata Location Location String)
22-
(define-struct (pcdata source) (string) #:transparent)
84+
(define-xexpr-struct (pcdata source) (string))
2385

2486
; Cdata = (make-cdata Location Location String)
25-
(define-struct (cdata source) (string) #:transparent)
87+
(define-xexpr-struct (cdata source) (string))
2688

2789
; Section 2.2 of XML 1.1
2890
; (XML 1.0 is slightly different and more restrictive)

racket/collects/xml/private/structures.rkt

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,45 @@
11
#lang racket/base
22
(require "core.rkt"
3-
racket/contract)
3+
(submod "core.rkt" serialization-support)
4+
racket/runtime-path
5+
racket/contract
6+
(for-syntax racket/base))
7+
8+
(define-runtime-module-path-index deserialize-info-mpi '(submod "." deserialize-info))
9+
(module+ deserialize-info
10+
(define-syntax-rule (get-checked-constructor name)
11+
(let ()
12+
(local-require (only-in (submod "..") name))
13+
name)))
14+
(define-syntax define-xml-struct
15+
(make-define-serializable-struct #'deserialize-info-mpi #'get-checked-constructor))
416

517
; Location = (make-location Nat Nat Nat) | Symbol
6-
(define-struct location (line char offset) #:transparent)
18+
(define-xml-struct location (line char offset))
719

820
; Document = (make-document Prolog Element (listof Misc))
9-
(define-struct document (prolog element misc) #:transparent)
21+
(define-xml-struct document (prolog element misc))
1022

1123
; Prolog = (make-prolog (listof Misc) Document-type (listof Misc))
12-
(define-struct prolog (misc dtd misc2) #:transparent)
24+
(define-xml-struct prolog (misc dtd misc2))
1325

1426
; Document-type = (make-document-type sym External-dtd #f)
1527
; | #f
16-
(define-struct document-type (name external inlined) #:transparent)
28+
(define-xml-struct document-type (name external inlined))
1729

1830
; External-dtd = (make-external-dtd/public str str)
1931
; | (make-external-dtd/system str)
2032
; | #f
21-
(define-struct external-dtd (system) #:transparent)
22-
(define-struct (external-dtd/public external-dtd) (public) #:transparent)
23-
(define-struct (external-dtd/system external-dtd) () #:transparent)
33+
; NOTE, however, that the contract on `document-type` allows any `external-dtd?`
34+
(define-xml-struct external-dtd (system))
35+
(define-xml-struct (external-dtd/public external-dtd) (public))
36+
(define-xml-struct (external-dtd/system external-dtd) ())
2437

2538
; Element = (make-element Location Location Symbol (listof Attribute) (listof Content))
26-
(define-struct (element source) (name attributes content) #:transparent)
39+
(define-xml-struct (element source) (name attributes content))
2740

2841
; Attribute = (make-attribute Location Location Symbol String)
29-
(define-struct (attribute source) (name value) #:transparent)
42+
(define-xml-struct (attribute source) (name value))
3043

3144
; Content = Pcdata
3245
; | Element
@@ -38,7 +51,7 @@
3851
; | Processing-instruction
3952

4053
; Entity = (make-entity Location Location (U Nat Symbol))
41-
(define-struct (entity source) (text) #:transparent)
54+
(define-xml-struct (entity source) (text))
4255

4356
(define permissive/c
4457
(make-contract

0 commit comments

Comments
 (0)