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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
use crate::*;

#[derive(Clone, Debug)]
pub enum StandardObject {
    Device(Device),
    People(People),
    SimpleGroup(SimpleGroup),
    Org(Org),
    AppGroup(AppGroup),
    UnionAccount(UnionAccount),
    ChunkId(ChunkId),
    File(File),
    Dir(Dir),
    Diff(Diff),
    ProofOfService(ProofOfService),
    Tx(Tx),
    Action(Action),
    ObjectMap(ObjectMap),
    Contract(Contract),
}

#[macro_export]
macro_rules! match_standard_obj {
    ($on:ident, $o:ident, $body:tt, $chunk_id:ident, $chunk_body:tt) => {
        match $on {
            StandardObject::Device($o) => $body,
            StandardObject::People($o) => $body,
            StandardObject::SimpleGroup($o) => $body,
            StandardObject::Org($o) => $body,
            StandardObject::AppGroup($o) => $body,
            StandardObject::UnionAccount($o) => $body,
            StandardObject::ChunkId($chunk_id) => $chunk_body,
            StandardObject::File($o) => $body,
            StandardObject::Dir($o) => $body,
            StandardObject::Diff($o) => $body,
            StandardObject::ProofOfService($o) => $body,
            StandardObject::Tx($o) => $body,
            StandardObject::Action($o) => $body,
            StandardObject::ObjectMap($o) => $body,
            StandardObject::Contract($o) => $body,
        }
    };
}

macro_rules! match_standard_owner_obj {
    ($on:ident, $o:ident, $body:tt, $other_body:tt) => {
        match $on {
            StandardObject::Device($o) => $body,
            StandardObject::People($o) => $body,
            StandardObject::Contract($o) => $body,
            StandardObject::File($o) => $body,
            StandardObject::Dir($o) => $body,
            StandardObject::Diff($o) => $body,
            StandardObject::ProofOfService($o) => $body,
            StandardObject::Action($o) => $body,
            StandardObject::ObjectMap($o) => $body,
            _ => $other_body,
        }
    };
}

macro_rules! match_standard_pubkey_obj {
    ($on:ident, $o:ident, $body:tt, $other_body:tt) => {
        match $on {
            StandardObject::Device($o) => $body,
            StandardObject::People($o) => $body,
            StandardObject::SimpleGroup($o) => $body,
            _ => $other_body,
        }
    };
}

macro_rules! match_standard_author_obj {
    ($on:ident, $o:ident, $body:tt, $other_body:tt) => {
        match $on {
            StandardObject::File($o) => $body,
            StandardObject::Contract($o) => $body,
            _ => $other_body,
        }
    };
}

macro_rules! match_standard_ood_list_obj {
    ($on:ident, $o:ident, $body:tt, $other_body:tt) => {
        match $on {
            StandardObject::SimpleGroup($o) => $body,
            StandardObject::People($o) => $body,
            _ => $other_body,
        }
    };
}

impl StandardObject {
    pub fn calculate_id(&self) -> ObjectId {
        match_standard_obj!(self, o, { o.desc().calculate_id() }, chunk_id, {
            chunk_id.object_id()
        })
    }

    pub fn obj_type(&self) -> BuckyResult<u16> {
        match_standard_obj!(self, o, { Ok(o.desc().obj_type()) }, _chunk_id, {
            Ok(ObjectTypeCode::Chunk.to_u16())
        })
    }

    pub fn obj_type_code(&self) -> ObjectTypeCode {
        match_standard_obj!(self, o, { o.desc().obj_type_code() }, _chunk_id, {
            ObjectTypeCode::Chunk
        })
    }

    pub fn dec_id(&self) -> &Option<ObjectId> {
        match_standard_obj!(self, o, { o.desc().dec_id() }, _chunk_id, { &None })
    }

    pub fn owner(&self) -> &Option<ObjectId> {
        match_standard_owner_obj!(self, o, { o.desc().owner() }, { &None })
    }

    pub fn prev(&self) -> &Option<ObjectId> {
        match_standard_owner_obj!(self, o, { o.desc().prev() }, { &None })
    }

    pub fn public_key(&self) -> Option<PublicKeyRef> {
        match_standard_pubkey_obj!(self, o, { o.desc().public_key_ref() }, { None })
    }

    pub fn author(&self) -> &Option<ObjectId> {
        match_standard_author_obj!(self, o, { o.desc().author() }, { &None })
    }

    pub fn ood_list(&self) -> BuckyResult<&Vec<DeviceId>> {
        match_standard_ood_list_obj!(
            self,
            o,
            {
                let b = o.body().as_ref();
                if b.is_none() {
                    Err(BuckyError::new(BuckyErrorCode::NotFound, "missing body"))
                } else {
                    let b = b.unwrap();
                    Ok(b.content().ood_list())
                }
            },
            { Err(BuckyError::new(BuckyErrorCode::NotSupport, "ood_list not support")) }
        )
    }

    pub fn ood_work_mode(&self) -> BuckyResult<OODWorkMode> {
        match_standard_ood_list_obj!(
            self,
            o,
            {
                let b = o.body().as_ref();
                if b.is_none() {
                    Err(BuckyError::new(BuckyErrorCode::NotFound, "missing body"))
                } else {
                    let b = b.unwrap();
                    Ok(b.content().ood_work_mode())
                }
            },
            { Err(BuckyError::new(BuckyErrorCode::NotSupport, "ood_work_mode not support")) }
        )
    }
}

impl RawEncode for StandardObject {
    fn raw_measure(&self, purpose: &Option<RawEncodePurpose>) -> BuckyResult<usize> {
        match self {
            StandardObject::Device(o) => o.raw_measure(purpose),
            StandardObject::People(o) => o.raw_measure(purpose),
            StandardObject::SimpleGroup(o) => o.raw_measure(purpose),
            StandardObject::Org(o) => o.raw_measure(purpose),
            StandardObject::AppGroup(o) => o.raw_measure(purpose),
            StandardObject::UnionAccount(o) => o.raw_measure(purpose),
            StandardObject::ChunkId(o) => o.raw_measure(purpose),
            StandardObject::File(o) => o.raw_measure(purpose),
            StandardObject::Dir(o) => o.raw_measure(purpose),
            StandardObject::Diff(o) => o.raw_measure(purpose),
            StandardObject::ProofOfService(o) => o.raw_measure(purpose),
            StandardObject::Tx(o) => o.raw_measure(purpose),
            StandardObject::Action(o) => o.raw_measure(purpose),
            StandardObject::ObjectMap(o) => o.raw_measure(purpose),
            StandardObject::Contract(o) => o.raw_measure(purpose),
        }
    }

    fn raw_encode<'a>(
        &self,
        buf: &'a mut [u8],
        purpose: &Option<RawEncodePurpose>,
    ) -> BuckyResult<&'a mut [u8]> {
        match self {
            StandardObject::Device(o) => o.raw_encode(buf, purpose),
            StandardObject::People(o) => o.raw_encode(buf, purpose),
            StandardObject::SimpleGroup(o) => o.raw_encode(buf, purpose),
            StandardObject::Org(o) => o.raw_encode(buf, purpose),
            StandardObject::AppGroup(o) => o.raw_encode(buf, purpose),
            StandardObject::UnionAccount(o) => o.raw_encode(buf, purpose),
            StandardObject::ChunkId(o) => o.raw_encode(buf, purpose),
            StandardObject::File(o) => o.raw_encode(buf, purpose),
            StandardObject::Dir(o) => o.raw_encode(buf, purpose),
            StandardObject::Diff(o) => o.raw_encode(buf, purpose),
            StandardObject::ProofOfService(o) => o.raw_encode(buf, purpose),
            StandardObject::Tx(o) => o.raw_encode(buf, purpose),
            StandardObject::Action(o) => o.raw_encode(buf, purpose),
            StandardObject::ObjectMap(o) => o.raw_encode(buf, purpose),
            StandardObject::Contract(o) => o.raw_encode(buf, purpose),
        }
    }
}

// 通用的单个对象解码器
impl<'de> RawDecode<'de> for StandardObject {
    fn raw_decode(buf: &'de [u8]) -> BuckyResult<(Self, &'de [u8])> {
        let (ctx, _) = NamedObjectContext::raw_decode(buf).map_err(|e| {
            log::error!("StandardObject::raw_decode/NamedObjectContext error:{}", e);
            e
        })?;

        match ctx.obj_type_code() {
            ObjectTypeCode::Device => {
                Device::raw_decode(buf).map(|(obj, buf)| (StandardObject::Device(obj), buf))
            }
            ObjectTypeCode::People => {
                People::raw_decode(buf).map(|(obj, buf)| (StandardObject::People(obj), buf))
            }
            ObjectTypeCode::SimpleGroup => SimpleGroup::raw_decode(buf)
                .map(|(obj, buf)| (StandardObject::SimpleGroup(obj), buf)),
            ObjectTypeCode::Org => {
                Org::raw_decode(buf).map(|(obj, buf)| (StandardObject::Org(obj), buf))
            }
            ObjectTypeCode::AppGroup => {
                AppGroup::raw_decode(buf).map(|(obj, buf)| (StandardObject::AppGroup(obj), buf))
            }
            ObjectTypeCode::UnionAccount => UnionAccount::raw_decode(buf)
                .map(|(obj, buf)| (StandardObject::UnionAccount(obj), buf)),
            ObjectTypeCode::Chunk => {
                ChunkId::raw_decode(buf).map(|(obj, buf)| (StandardObject::ChunkId(obj), buf))
            }
            ObjectTypeCode::File => {
                File::raw_decode(buf).map(|(obj, buf)| (StandardObject::File(obj), buf))
            }
            ObjectTypeCode::Dir => {
                Dir::raw_decode(buf).map(|(obj, buf)| (StandardObject::Dir(obj), buf))
            }
            ObjectTypeCode::Diff => {
                Diff::raw_decode(buf).map(|(obj, buf)| (StandardObject::Diff(obj), buf))
            }
            ObjectTypeCode::ProofOfService => ProofOfService::raw_decode(buf)
                .map(|(obj, buf)| (StandardObject::ProofOfService(obj), buf)),
            ObjectTypeCode::Tx => {
                Tx::raw_decode(buf).map(|(obj, buf)| (StandardObject::Tx(obj), buf))
            }
            ObjectTypeCode::Action => {
                Action::raw_decode(buf).map(|(obj, buf)| (StandardObject::Action(obj), buf))
            }
            ObjectTypeCode::ObjectMap => {
                ObjectMap::raw_decode(buf).map(|(obj, buf)| (StandardObject::ObjectMap(obj), buf))
            }
            ObjectTypeCode::Contract => {
                Contract::raw_decode(buf).map(|(obj, buf)| (StandardObject::Contract(obj), buf))
            }
            _ => {
                unreachable!();
            }
        }
    }
}