-
Notifications
You must be signed in to change notification settings - Fork 6
/
answer.go
130 lines (108 loc) · 3.92 KB
/
answer.go
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package participation
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/iotaledger/hive.go/serializer/v2"
)
const (
AnswerTextMaxLength = 255
AnswerAdditionalInfoMaxLength = 500
AnswerValueSkipped = 0
AnswerValueInvalid = 255
)
var (
ErrSerializationReservedValue = errors.New("reserved value used")
)
// Answer is a possible answer to a Ballot Question.
type Answer struct {
// Value is the value that should be used to pick this answer. It must be unique for each answer in a given question. Reserved values are 0 and 255.
Value uint8
// Text is the text of the answer.
Text string
// AdditionalInfo is an additional description text about the answer.
AdditionalInfo string
}
func (a *Answer) Deserialize(data []byte, deSeriMode serializer.DeSerializationMode, _ interface{}) (int, error) {
return serializer.NewDeserializer(data).
ReadNum(&a.Value, func(err error) error {
return fmt.Errorf("unable to deserialize participation answer value: %w", err)
}).
ReadString(&a.Text, serializer.SeriLengthPrefixTypeAsByte, func(err error) error {
return fmt.Errorf("unable to deserialize participation answer text: %w", err)
}, 0, AnswerTextMaxLength).
ReadString(&a.AdditionalInfo, serializer.SeriLengthPrefixTypeAsUint16, func(err error) error {
return fmt.Errorf("unable to deserialize participation answer additional info: %w", err)
}, 0, AnswerAdditionalInfoMaxLength).
AbortIf(func(err error) error {
if deSeriMode.HasMode(serializer.DeSeriModePerformValidation) {
if a.Value == AnswerValueSkipped || a.Value == AnswerValueInvalid {
return fmt.Errorf("%w: answer is using a reserved value %d", ErrSerializationReservedValue, a.Value)
}
}
return nil
}).
Done()
}
func (a *Answer) Serialize(deSeriMode serializer.DeSerializationMode, _ interface{}) ([]byte, error) {
return serializer.NewSerializer().
AbortIf(func(err error) error {
if deSeriMode.HasMode(serializer.DeSeriModePerformValidation) {
if a.Value == AnswerValueSkipped || a.Value == AnswerValueInvalid {
return fmt.Errorf("%w: answer is using a reserved value %d", ErrSerializationReservedValue, a.Value)
}
}
return nil
}).
WriteNum(a.Value, func(err error) error {
return fmt.Errorf("unable to serialize participation answer index: %w", err)
}).
WriteString(a.Text, serializer.SeriLengthPrefixTypeAsByte, func(err error) error {
return fmt.Errorf("unable to serialize participation answer text: %w", err)
}, 0, AnswerTextMaxLength).
WriteString(a.AdditionalInfo, serializer.SeriLengthPrefixTypeAsUint16, func(err error) error {
return fmt.Errorf("unable to serialize participation answer additional info: %w", err)
}, 0, AnswerAdditionalInfoMaxLength).
Serialize()
}
func (a *Answer) MarshalJSON() ([]byte, error) {
jAnswer := &jsonAnswer{
Value: a.Value,
Text: a.Text,
AdditionalInfo: a.AdditionalInfo,
}
return json.Marshal(jAnswer)
}
func (a *Answer) UnmarshalJSON(bytes []byte) error {
jAnswer := &jsonAnswer{}
if err := json.Unmarshal(bytes, jAnswer); err != nil {
return err
}
seri, err := jAnswer.ToSerializable()
if err != nil {
return err
}
answer, ok := seri.(*Answer)
if !ok {
panic(fmt.Sprintf("invalid type: expected *Answer, got %T", seri))
}
*a = *answer
return nil
}
// jsonAnswer defines the json representation of an Answer.
type jsonAnswer struct {
// Value is the value that should be used to pick this answer. It must be unique for each answer in a given question. Reserved values are 0 and 255.
Value uint8 `json:"value"`
// Text is the text of the answer.
Text string `json:"text"`
// AdditionalInfo is an additional description text about the answer.
AdditionalInfo string `json:"additionalInfo"`
}
func (j *jsonAnswer) ToSerializable() (serializer.Serializable, error) {
payload := &Answer{
Value: j.Value,
Text: j.Text,
AdditionalInfo: j.AdditionalInfo,
}
return payload, nil
}