Skip to content
This repository was archived by the owner on Dec 1, 2024. It is now read-only.

Commit aeb5320

Browse files
Jesse CorettaJesse Coretta
Jesse Coretta
authored and
Jesse Coretta
committed
preliminary marshal support
1 parent 4317fce commit aeb5320

19 files changed

+1033
-21
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# go-schemax
22

3-
Package schemax incorporates a powerful [RFC 4512](https://www.rfc-editor.org/rfc/rfc4512.txt) parser, wrapped with convenient, reflective features for creating and interrogating directory schemas.
3+
Package schemax (_`skee·muh·eks`_) incorporates a powerful [RFC 4512](https://www.rfc-editor.org/rfc/rfc4512.txt) parser, wrapped with convenient, reflective features for creating and interrogating directory schemas.
44

55
Requires Go version 1.22 or higher.
66

@@ -110,6 +110,10 @@ The general rule-of-thumb is suggests that if the `ls -l` Bash command _consiste
110110

111111
The `ParseRaw` method is subject to the same conditions related to the order of dependent definitions.
112112

113+
## Marshal support
114+
115+
When needed, all `Definition` qualifier types allow for convenient population by way of an instance of `DefinitionMap` or `map[string]any` being submitted to the appropriate `Marshal` method held by the desired receiver instance. This feature bridges the gap between other markdown languages, such as JSON, and allows easy conversion into the desired definition type.
116+
113117
## The Schema Itself
114118

115119
The `Schema` type defined within this package is a [`stackage.Stack`](https://pkg.go.dev/github.com/JesseCoretta/go-stackage#Stack) derivative type. An instance of a `Schema` can manifest in any of the following manners:

at.go

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,107 @@ func newAttributeType() *attributeType {
5858
}
5959
}
6060

61+
/*
62+
Marshal returns an error following an attempt to marshal the contents of
63+
def, which may be either a [DefinitionMap] or map[string]any instance.
64+
65+
The receiver instance must be initialized prior to use of this method
66+
using the [Schema.AttributeType] method.
67+
*/
68+
func (r AttributeType) Marshal(def any) error {
69+
m, err := getMarshalMap(r, def)
70+
if err != nil {
71+
return err
72+
}
73+
74+
for k, v := range m {
75+
switch key := uc(k); key {
76+
case `NAME`:
77+
switch tv := v.(type) {
78+
case string:
79+
r.SetName(tv)
80+
case []string:
81+
r.SetName(tv...)
82+
}
83+
case `NUMERICOID`, `DESC`:
84+
z := map[string]func(string) AttributeType{
85+
`DESC`: r.SetDescription,
86+
`NUMERICOID`: r.SetNumericOID,
87+
}
88+
switch tv := v.(type) {
89+
case string:
90+
z[k](tv)
91+
case []string:
92+
z[k](tv[0])
93+
}
94+
case `OBSOLETE`, `COLLECTIVE`,
95+
`NO-USER-MODIFICATION`, `SINGLE-VALUE`:
96+
z := map[string]func() AttributeType{
97+
`OBSOLETE`: r.SetObsolete,
98+
`NO-USER-MODIFICATION`: r.SetNoUserModification,
99+
`COLLECTIVE`: r.SetCollective,
100+
`SINGLE-VALUE`: r.SetSingleValue,
101+
}
102+
103+
r.marshalBoolean(v, z[k])
104+
case `EQUALITY`, `SYNTAX`, `SUBSTRING`, `SUP`,
105+
`ORDERING`, `USAGE`, `SUBSTR`:
106+
z := map[string]func(any) AttributeType{
107+
`SUP`: r.SetSuperType,
108+
`SYNTAX`: r.SetSyntax,
109+
`EQUALITY`: r.SetEquality,
110+
`ORDERING`: r.SetOrdering,
111+
`SUBSTR`: r.SetSubstring,
112+
`SUBSTRING`: r.SetSubstring,
113+
`USAGE`: r.SetUsage,
114+
}
115+
switch tv := v.(type) {
116+
case string:
117+
z[k](tv)
118+
case []string:
119+
z[k](tv[0])
120+
}
121+
default:
122+
r.marshalExt(key, v)
123+
}
124+
}
125+
126+
if !r.Compliant() {
127+
return ErrDefNonCompliant
128+
}
129+
r.SetStringer()
130+
131+
return nil
132+
}
133+
134+
func (r AttributeType) marshalExt(key string, v any) {
135+
if hasPfx(key, `X-`) {
136+
switch tv := v.(type) {
137+
case string:
138+
r.SetExtension(key, tv)
139+
case []string:
140+
r.SetExtension(key, tv...)
141+
}
142+
}
143+
}
144+
145+
func (r AttributeType) marshalBoolean(v any, funk func() AttributeType) {
146+
switch tv := v.(type) {
147+
case string:
148+
if eq(tv, `TRUE`) {
149+
funk()
150+
}
151+
case []string:
152+
if eq(tv[0], `TRUE`) {
153+
funk()
154+
}
155+
case bool:
156+
if tv {
157+
funk()
158+
}
159+
}
160+
}
161+
61162
/*
62163
Parse returns an error following an attempt to parse raw into the receiver
63164
instance.
@@ -1452,9 +1553,9 @@ Note that a value of true will be ignored if the receiver is a collective
14521553
14531554
This is a fluent method.
14541555
*/
1455-
func (r AttributeType) SetSingleValue(x any) AttributeType {
1556+
func (r AttributeType) SetSingleValue() AttributeType {
14561557
if !r.IsZero() {
1457-
r.attributeType.setBoolean(`sv`, x)
1558+
r.attributeType.setBoolean(`sv`, true)
14581559
}
14591560

14601561
return r
@@ -1472,9 +1573,9 @@ Note that a value of true will be ignored if the receiver is a single-valued
14721573
14731574
This is a fluent method.
14741575
*/
1475-
func (r AttributeType) SetCollective(x any) AttributeType {
1576+
func (r AttributeType) SetCollective() AttributeType {
14761577
if !r.IsZero() {
1477-
r.attributeType.setBoolean(`c`, x)
1578+
r.attributeType.setBoolean(`c`, true)
14781579
}
14791580

14801581
return r
@@ -1489,9 +1590,9 @@ are used, case is not significant.
14891590
14901591
This is a fluent method.
14911592
*/
1492-
func (r AttributeType) SetNoUserModification(x any) AttributeType {
1593+
func (r AttributeType) SetNoUserModification() AttributeType {
14931594
if !r.IsZero() {
1494-
r.attributeType.setBoolean(`num`, x)
1595+
r.attributeType.setBoolean(`num`, true)
14951596
}
14961597

14971598
return r
@@ -1504,20 +1605,14 @@ Obsolescence cannot be unset.
15041605
15051606
This is a fluent method.
15061607
*/
1507-
func (r AttributeType) SetObsolete(x any) AttributeType {
1608+
func (r AttributeType) SetObsolete() AttributeType {
15081609
if !r.IsZero() {
1509-
r.attributeType.setObsolete()
1610+
r.attributeType.setBoolean(`obs`, true)
15101611
}
15111612

15121613
return r
15131614
}
15141615

1515-
func (r *attributeType) setObsolete() {
1516-
if !r.Obsolete {
1517-
r.Obsolete = true
1518-
}
1519-
}
1520-
15211616
func (r *attributeType) setBoolean(t string, x any) {
15221617

15231618
var Bool bool

at_test.go

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,47 @@ import (
99
"unicode/utf8"
1010
)
1111

12+
/*
13+
This example demonstrates the means for marshaling an instance of
14+
[AttributeType] from a map[string]any instance.
15+
*/
16+
func ExampleAttributeType_Marshal() {
17+
m := map[string]any{
18+
`NAME`: `exampleAttributeType`,
19+
`DESC`: `This is an example`,
20+
`NUMERICOID`: `1.3.6.1.4.1.56521.999.12.34.56`,
21+
`COLLECTIVE`: `FALSE`,
22+
`NO-USER-MODIFICATION`: `TRUE`,
23+
`SINGLE-VALUE`: `TRUE`,
24+
`OBSOLETE`: `FALSE`,
25+
`EQUALITY`: `integerMatch`,
26+
`ORDERING`: `integerOrderingMatch`,
27+
`SUBSTR`: `caseIgnoreSubstringsMatch`,
28+
`SYNTAX`: `1.3.6.1.4.1.1466.115.121.1.27`,
29+
`USAGE`: `dSAOperation`,
30+
`X-ORIGIN`: `RFCXXXX`,
31+
}
32+
33+
var def AttributeType = mySchema.NewAttributeType()
34+
if err := def.Marshal(m); err != nil {
35+
fmt.Println(err)
36+
return
37+
}
38+
39+
fmt.Printf("%s\n", def)
40+
// Output: ( 1.3.6.1.4.1.56521.999.12.34.56
41+
// NAME 'exampleAttributeType'
42+
// DESC 'This is an example'
43+
// EQUALITY integerMatch
44+
// SUBSTR caseIgnoreSubstringsMatch
45+
// ORDERING integerOrderingMatch
46+
// SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
47+
// SINGLE-VALUE
48+
// NO-USER-MODIFICATION
49+
// USAGE dSAOperation
50+
// X-ORIGIN 'RFCXXXX' )
51+
}
52+
1253
/*
1354
This example demonstrates the means of gathering references to every
1455
superior [AttributeType] in the relevant super type chain.
@@ -285,7 +326,7 @@ func ExampleNewAttributeType() {
285326
SetSyntax(dStr).
286327
SetMinimumUpperBounds(64).
287328
SetEquality(cIM).
288-
SetSingleValue(true).
329+
SetSingleValue().
289330
SetExtension(`X-ORIGIN`, `NOWHERE`).
290331
SetStringer() // use default stringer
291332

@@ -1053,11 +1094,11 @@ func TestAttributeType_codecov(t *testing.T) {
10531094
}
10541095
zz.superChain()
10551096
zz.setSuperType(mySchema.AttributeTypes().Get(`cn`))
1056-
zz.SetCollective(rune(88))
1057-
zz.SetCollective(true)
1058-
zz.SetObsolete(true)
1059-
zz.SetObsolete(`true`)
1060-
zz.SetNoUserModification(true)
1097+
zz.SetCollective()
1098+
zz.SetCollective()
1099+
zz.SetObsolete()
1100+
zz.SetObsolete()
1101+
zz.SetNoUserModification()
10611102
zz.SetUsage(`directoryOperation`)
10621103
zz.Usage()
10631104
zz.SetUsage(`distributedOperation`)

dc.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,101 @@ func (r DITContentRule) mayComply(must, may AttributeTypes) bool {
624624
return true
625625
}
626626

627+
/*
628+
Marshal returns an error following an attempt to marshal the contents of
629+
def, which may be either a [DefinitionMap] or map[string]any instance.
630+
631+
The receiver instance must be initialized prior to use of this method
632+
using the [Schema.NewDITContentRule] method.
633+
*/
634+
func (r DITContentRule) Marshal(def any) error {
635+
m, err := getMarshalMap(r, def)
636+
if err != nil {
637+
return err
638+
}
639+
640+
for k, v := range m {
641+
switch key := uc(k); key {
642+
case `NAME`:
643+
switch tv := v.(type) {
644+
case string:
645+
r.SetName(tv)
646+
case []string:
647+
r.SetName(tv...)
648+
}
649+
case `NUMERICOID`, `DESC`:
650+
z := map[string]func(string) DITContentRule{
651+
`DESC`: r.SetDescription,
652+
`NUMERICOID`: r.SetNumericOID,
653+
}
654+
switch tv := v.(type) {
655+
case string:
656+
z[k](tv)
657+
case []string:
658+
z[k](tv[0])
659+
}
660+
case `OBSOLETE`:
661+
r.marshalBoolean(v)
662+
case `MUST`, `MAY`, `NOT`, `AUX`:
663+
r.marshalMulti(key, v)
664+
default:
665+
r.marshalExt(key, v)
666+
}
667+
}
668+
669+
if !r.Compliant() {
670+
return ErrDefNonCompliant
671+
}
672+
r.SetStringer()
673+
674+
return nil
675+
}
676+
677+
func (r DITContentRule) marshalBoolean(v any) {
678+
switch tv := v.(type) {
679+
case string:
680+
if eq(tv, `TRUE`) {
681+
r.SetObsolete()
682+
}
683+
case []string:
684+
if eq(tv[0], `TRUE`) {
685+
r.SetObsolete()
686+
}
687+
case bool:
688+
if tv {
689+
r.SetObsolete()
690+
}
691+
}
692+
}
693+
694+
func (r DITContentRule) marshalExt(key string, v any) {
695+
if hasPfx(key, `X-`) {
696+
switch tv := v.(type) {
697+
case string:
698+
r.SetExtension(key, tv)
699+
case []string:
700+
r.SetExtension(key, tv...)
701+
}
702+
}
703+
}
704+
705+
func (r DITContentRule) marshalMulti(k string, v any) {
706+
z := map[string]func(...any) DITContentRule{
707+
`MUST`: r.SetMust,
708+
`MAY`: r.SetMay,
709+
`NOT`: r.SetNot,
710+
`AUX`: r.SetAux,
711+
}
712+
switch tv := v.(type) {
713+
case []string:
714+
for i := 0; i < len(tv); i++ {
715+
z[k](tv[i])
716+
}
717+
case string:
718+
z[k](tv)
719+
}
720+
}
721+
627722
/*
628723
Parse returns an error following an attempt to parse raw into the receiver
629724
instance.

0 commit comments

Comments
 (0)