@@ -25,15 +25,26 @@ func BindInstanceType[T Assignee](inst *Instance, tsch TypedSchema[T]) (*TypedIn
25
25
}, nil
26
26
}
27
27
28
- // An Instance represents some data that has been validated against a
29
- // lineage's schema. It includes a reference to the schema.
28
+ // Instance represents data that is a valid instance of a Thema [Schema].
29
+ //
30
+ // It is not possible to create a valid Instance directly. They can only be
31
+ // obtained by successful call to [Schema.Validate].
30
32
type Instance struct {
31
33
// The CUE representation of the input data
32
34
raw cue.Value
33
35
// A name for the input data, primarily for use in error messages
34
36
name string
35
37
// The schema the data validated against/of which the input data is a valid instance
36
38
sch Schema
39
+
40
+ // simple flag the prevents external creation
41
+ valid bool
42
+ }
43
+
44
+ func (i * Instance ) check () {
45
+ if ! i .valid {
46
+ panic ("Instance is not valid; Instances must be created by a call to thema.Schema.Validate" )
47
+ }
37
48
}
38
49
39
50
// Hydrate returns a copy of the Instance with all default values specified by
@@ -42,6 +53,8 @@ type Instance struct {
42
53
// NOTE hydration implementation is a WIP. If errors are encountered, the
43
54
// original input is returned unchanged.
44
55
func (i * Instance ) Hydrate () * Instance {
56
+ i .check ()
57
+
45
58
i .sch .Lineage ().Runtime ()
46
59
ni , err := doHydrate (i .sch .Underlying (), i .raw )
47
60
// FIXME For now, just no-op it if we error
@@ -50,9 +63,10 @@ func (i *Instance) Hydrate() *Instance {
50
63
}
51
64
52
65
return & Instance {
53
- raw : ni ,
54
- name : i .name ,
55
- sch : i .sch ,
66
+ valid : true ,
67
+ raw : ni ,
68
+ name : i .name ,
69
+ sch : i .sch ,
56
70
}
57
71
}
58
72
@@ -62,66 +76,90 @@ func (i *Instance) Hydrate() *Instance {
62
76
// NOTE dehydration implementation is a WIP. If errors are encountered, the
63
77
// original input is returned unchanged.
64
78
func (i * Instance ) Dehydrate () * Instance {
79
+ i .check ()
80
+
65
81
ni , _ , err := doDehydrate (i .sch .Underlying (), i .raw )
66
82
// FIXME For now, just no-op it if we error
67
83
if err != nil {
68
84
return i
69
85
}
70
86
71
87
return & Instance {
72
- raw : ni ,
73
- name : i .name ,
74
- sch : i .sch ,
88
+ valid : true ,
89
+ raw : ni ,
90
+ name : i .name ,
91
+ sch : i .sch ,
75
92
}
76
93
}
77
94
78
95
// AsSuccessor translates the instance into the form specified by the successor
79
96
// schema.
80
- //
81
- // TODO figure out how to represent unary vs. composite lineages here
82
97
func (i * Instance ) AsSuccessor () (* Instance , TranslationLacunas ) {
98
+ i .check ()
83
99
return i .Translate (i .sch .Successor ().Version ())
84
100
}
85
101
86
102
// AsPredecessor translates the instance into the form specified by the predecessor
87
103
// schema.
88
- //
89
- // TODO figure out how to represent unary vs. composite lineages here
90
104
func (i * Instance ) AsPredecessor () (* Instance , TranslationLacunas ) {
91
- panic ("TODO translation from newer to older schema is not yet implemented" )
105
+ i .check ()
106
+ return i .Translate (i .sch .Predecessor ().Version ())
92
107
}
93
108
94
- // Underlying returns the cue.Value representing the instance's underlying data .
109
+ // Underlying returns the cue.Value representing the data contained in the Instance .
95
110
func (i * Instance ) Underlying () cue.Value {
111
+ i .check ()
96
112
return i .raw
97
113
}
98
114
99
- // Schema returns the schema which subsumes/validated this instance.
115
+ // Schema returns the [Schema] corresponding to this instance.
100
116
func (i * Instance ) Schema () Schema {
117
+ i .check ()
101
118
return i .sch
102
119
}
103
120
104
121
func (i * Instance ) rt () * Runtime {
105
122
return getLinLib (i .Schema ().Lineage ())
106
123
}
107
124
125
+ // TypedInstance represents data that is a valid instance of a Thema
126
+ // [TypedSchema].
127
+ //
128
+ // A TypedInstance is to a [TypedSchema] as an [Instance] is to a [Schema].
129
+ //
130
+ // It is not possible to create a valid TypedInstance directly. They can only be
131
+ // obtained by successful call to [TypedSchema.Validate].
108
132
type TypedInstance [T Assignee ] struct {
109
133
* Instance
110
134
tsch TypedSchema [T ]
111
135
}
112
136
137
+ // TypedSchema returns the [TypedSchema] corresponding to this instance.
138
+ //
139
+ // This method is identical to [Instance.Schema], except that it returns the already-typed variant.
113
140
func (inst * TypedInstance [T ]) TypedSchema () TypedSchema [T ] {
141
+ inst .check ()
114
142
return inst .tsch
115
143
}
116
144
145
+ // Value returns a Go struct of this TypedInstance's generic [Assignee] type,
146
+ // populated with the data contained in this instance, including default values, etc.
147
+ //
148
+ // This method is similar to [json.Unmarshal] - it decodes serialized data into a standard Go type
149
+ // for working with in all the usual ways.
117
150
func (inst * TypedInstance [T ]) Value () (T , error ) {
151
+ inst .check ()
152
+
118
153
t := inst .tsch .NewT ()
119
154
// TODO figure out correct pointer handling here
120
155
err := inst .Instance .raw .Decode (& t )
121
156
return t , err
122
157
}
123
158
159
+ // ValueP is the same as Value, but panics if an error is encountered.
124
160
func (inst * TypedInstance [T ]) ValueP () T {
161
+ inst .check ()
162
+
125
163
t , err := inst .Value ()
126
164
if err != nil {
127
165
panic (fmt .Errorf ("error decoding value: %w" , err ))
@@ -150,6 +188,8 @@ func (inst *TypedInstance[T]) ValueP() T {
150
188
// achieved in the program depending on Thema, so we avoid introducing
151
189
// complexity into Thema that is not essential for all use cases.
152
190
func (i * Instance ) Translate (to SyntacticVersion ) (* Instance , TranslationLacunas ) {
191
+ i .check ()
192
+
153
193
// TODO define this in terms of AsSuccessor and AsPredecessor, rather than those in terms of this.
154
194
newsch , err := i .Schema ().Lineage ().Schema (to )
155
195
if err != nil {
@@ -179,9 +219,10 @@ func (i *Instance) Translate(to SyntacticVersion) (*Instance, TranslationLacunas
179
219
raw , _ := out .LookupPath (cue .MakePath (cue .Str ("result" ), cue .Str ("result" ))).Default ()
180
220
181
221
return & Instance {
182
- raw : raw ,
183
- name : i .name ,
184
- sch : newsch ,
222
+ valid : true ,
223
+ raw : raw ,
224
+ name : i .name ,
225
+ sch : newsch ,
185
226
}, lac
186
227
}
187
228
0 commit comments