sui_rpc/proto/sui/rpc/v2/
object.rs1use super::*;
2use crate::field::FieldMaskTree;
3use crate::merge::Merge;
4use crate::proto::TryFromProtoError;
5use tap::Pipe;
6
7pub const PACKAGE_TYPE: &str = "package";
12
13impl From<sui_sdk_types::Object> for Object {
14 fn from(value: sui_sdk_types::Object) -> Self {
15 Self::merge_from(value, &FieldMaskTree::new_wildcard())
16 }
17}
18
19impl Merge<&Object> for Object {
20 fn merge(&mut self, source: &Object, mask: &FieldMaskTree) {
21 let Object {
22 bcs,
23 object_id,
24 version,
25 digest,
26 owner,
27 object_type,
28 has_public_transfer,
29 contents,
30 package,
31 previous_transaction,
32 storage_rebate,
33 json,
34 balance,
35 display,
36 } = source;
37
38 if mask.contains(Self::BCS_FIELD.name) {
39 self.bcs = bcs.clone();
40 }
41
42 if mask.contains(Self::DIGEST_FIELD.name) {
43 self.digest = digest.clone();
44 }
45
46 if mask.contains(Self::OBJECT_ID_FIELD.name) {
47 self.object_id = object_id.clone();
48 }
49
50 if mask.contains(Self::VERSION_FIELD.name) {
51 self.version = *version;
52 }
53
54 if mask.contains(Self::OWNER_FIELD.name) {
55 self.owner = owner.clone();
56 }
57
58 if mask.contains(Self::PREVIOUS_TRANSACTION_FIELD.name) {
59 self.previous_transaction = previous_transaction.clone();
60 }
61
62 if mask.contains(Self::STORAGE_REBATE_FIELD.name) {
63 self.storage_rebate = *storage_rebate;
64 }
65
66 if mask.contains(Self::OBJECT_TYPE_FIELD.name) {
67 self.object_type = object_type.clone();
68 }
69
70 if mask.contains(Self::HAS_PUBLIC_TRANSFER_FIELD.name) {
71 self.has_public_transfer = *has_public_transfer;
72 }
73
74 if mask.contains(Self::CONTENTS_FIELD.name) {
75 self.contents = contents.clone();
76 }
77
78 if mask.contains(Self::PACKAGE_FIELD.name) {
79 self.package = package.clone();
80 }
81
82 if mask.contains(Self::JSON_FIELD.name) {
83 self.json = json.clone();
84 }
85
86 if mask.contains(Self::BALANCE_FIELD) {
87 self.balance = *balance;
88 }
89
90 if mask.contains(Self::DIGEST_FIELD) {
91 self.display = display.clone();
92 }
93 }
94}
95
96impl Merge<sui_sdk_types::Object> for Object {
97 fn merge(&mut self, source: sui_sdk_types::Object, mask: &FieldMaskTree) {
98 if mask.contains(Self::BCS_FIELD.name) {
99 let mut bcs = Bcs::serialize(&source).unwrap();
100 bcs.name = Some("Object".to_owned());
101 self.bcs = Some(bcs);
102 }
103
104 if mask.contains(Self::DIGEST_FIELD.name) {
105 self.digest = Some(source.digest().to_string());
106 }
107
108 if mask.contains(Self::OBJECT_ID_FIELD.name) {
109 self.object_id = Some(source.object_id().to_string());
110 }
111
112 if mask.contains(Self::VERSION_FIELD.name) {
113 self.version = Some(source.version());
114 }
115
116 if mask.contains(Self::OWNER_FIELD.name) {
117 self.owner = Some(source.owner().to_owned().into());
118 }
119
120 if mask.contains(Self::PREVIOUS_TRANSACTION_FIELD.name) {
121 self.previous_transaction = Some(source.previous_transaction().to_string());
122 }
123
124 if mask.contains(Self::STORAGE_REBATE_FIELD.name) {
125 self.storage_rebate = Some(source.storage_rebate());
126 }
127
128 match source.data() {
129 sui_sdk_types::ObjectData::Struct(move_struct) => {
130 self.merge(move_struct, mask);
131 }
132 sui_sdk_types::ObjectData::Package(move_package) => {
133 self.merge(move_package, mask);
134 }
135 }
136 }
137}
138
139impl Merge<&sui_sdk_types::MoveStruct> for Object {
140 fn merge(&mut self, source: &sui_sdk_types::MoveStruct, mask: &FieldMaskTree) {
141 if mask.contains(Self::OBJECT_TYPE_FIELD.name) {
142 self.object_type = Some(source.object_type().to_string());
143 }
144
145 if mask.contains(Self::HAS_PUBLIC_TRANSFER_FIELD.name) {
146 self.has_public_transfer = Some(source.has_public_transfer());
147 }
148
149 if mask.contains(Self::CONTENTS_FIELD.name) {
150 self.contents = Some(Bcs {
151 name: Some(source.object_type().to_string()),
152 value: Some(source.contents().to_vec().into()),
153 });
154 }
155 }
156}
157
158impl Merge<&sui_sdk_types::MovePackage> for Object {
159 fn merge(&mut self, source: &sui_sdk_types::MovePackage, mask: &FieldMaskTree) {
160 if mask.contains(Self::OBJECT_TYPE_FIELD.name) {
161 self.object_type = Some(PACKAGE_TYPE.to_owned());
162 }
163
164 if mask.contains(Self::PACKAGE_FIELD.name) {
165 self.package = Some(Package {
166 modules: source
167 .modules
168 .iter()
169 .map(|(name, contents)| Module {
170 name: Some(name.to_string()),
171 contents: Some(contents.clone().into()),
172 ..Default::default()
173 })
174 .collect(),
175 type_origins: source
176 .type_origin_table
177 .clone()
178 .into_iter()
179 .map(Into::into)
180 .collect(),
181 linkage: source
182 .linkage_table
183 .iter()
184 .map(
185 |(
186 original_id,
187 sui_sdk_types::UpgradeInfo {
188 upgraded_id,
189 upgraded_version,
190 },
191 )| {
192 Linkage {
193 original_id: Some(original_id.to_string()),
194 upgraded_id: Some(upgraded_id.to_string()),
195 upgraded_version: Some(*upgraded_version),
196 }
197 },
198 )
199 .collect(),
200
201 ..Default::default()
202 })
203 }
204 }
205}
206
207#[allow(clippy::result_large_err)]
208fn try_extract_struct(value: &Object) -> Result<sui_sdk_types::MoveStruct, TryFromProtoError> {
209 let version = value
210 .version
211 .ok_or_else(|| TryFromProtoError::missing("version"))?;
212
213 let object_type = value
214 .object_type()
215 .parse()
216 .map_err(|e| TryFromProtoError::invalid(Object::OBJECT_TYPE_FIELD, e))?;
217
218 let has_public_transfer = value
219 .has_public_transfer
220 .ok_or_else(|| TryFromProtoError::missing("has_public_transfer"))?;
221 let contents = value
222 .contents
223 .as_ref()
224 .ok_or_else(|| TryFromProtoError::missing("contents"))?
225 .value()
226 .to_vec();
227
228 sui_sdk_types::MoveStruct::new(object_type, has_public_transfer, version, contents).ok_or_else(
229 || TryFromProtoError::invalid(Object::CONTENTS_FIELD, "contents missing object_id"),
230 )
231}
232
233#[allow(clippy::result_large_err)]
234fn try_extract_package(value: &Object) -> Result<sui_sdk_types::MovePackage, TryFromProtoError> {
235 if value.object_type() != PACKAGE_TYPE {
236 return Err(TryFromProtoError::invalid(
237 Object::OBJECT_TYPE_FIELD,
238 format!(
239 "expected type {}, found {}",
240 PACKAGE_TYPE,
241 value.object_type()
242 ),
243 ));
244 }
245
246 let version = value
247 .version
248 .ok_or_else(|| TryFromProtoError::missing("version"))?;
249 let id = value
250 .object_id
251 .as_ref()
252 .ok_or_else(|| TryFromProtoError::missing("object_id"))?
253 .parse()
254 .map_err(|e| TryFromProtoError::invalid(Object::OBJECT_ID_FIELD, e))?;
255
256 let package = value
257 .package
258 .as_ref()
259 .ok_or_else(|| TryFromProtoError::missing("package"))?;
260 let modules = package
261 .modules
262 .iter()
263 .map(|module| {
264 let name = module
265 .name
266 .as_ref()
267 .ok_or_else(|| TryFromProtoError::missing("name"))?
268 .parse()
269 .map_err(|e| TryFromProtoError::invalid(Module::NAME_FIELD, e))?;
270
271 let contents = module
272 .contents
273 .as_ref()
274 .ok_or_else(|| TryFromProtoError::missing("contents"))?
275 .to_vec();
276
277 Ok((name, contents))
278 })
279 .collect::<Result<_, TryFromProtoError>>()?;
280
281 let type_origin_table = package
282 .type_origins
283 .iter()
284 .map(TryInto::try_into)
285 .collect::<Result<_, _>>()?;
286
287 let linkage_table = package
288 .linkage
289 .iter()
290 .map(|upgrade_info| {
291 let original_id = upgrade_info
292 .original_id
293 .as_ref()
294 .ok_or_else(|| TryFromProtoError::missing("original_id"))?
295 .parse()
296 .map_err(|e| TryFromProtoError::invalid(Linkage::ORIGINAL_ID_FIELD, e))?;
297
298 let upgraded_id = upgrade_info
299 .upgraded_id
300 .as_ref()
301 .ok_or_else(|| TryFromProtoError::missing("upgraded_id"))?
302 .parse()
303 .map_err(|e| TryFromProtoError::invalid(Linkage::UPGRADED_ID_FIELD, e))?;
304 let upgraded_version = upgrade_info
305 .upgraded_version
306 .ok_or_else(|| TryFromProtoError::missing("upgraded_version"))?;
307
308 Ok((
309 original_id,
310 sui_sdk_types::UpgradeInfo {
311 upgraded_id,
312 upgraded_version,
313 },
314 ))
315 })
316 .collect::<Result<_, TryFromProtoError>>()?;
317
318 Ok(sui_sdk_types::MovePackage {
319 id,
320 version,
321 modules,
322 type_origin_table,
323 linkage_table,
324 })
325}
326
327impl TryFrom<&Object> for sui_sdk_types::Object {
328 type Error = TryFromProtoError;
329
330 fn try_from(value: &Object) -> Result<Self, Self::Error> {
331 let owner = value
332 .owner
333 .as_ref()
334 .ok_or_else(|| TryFromProtoError::missing("owner"))?
335 .try_into()?;
336
337 let previous_transaction = value
338 .previous_transaction
339 .as_ref()
340 .ok_or_else(|| TryFromProtoError::missing("previous_transaction"))?
341 .parse()
342 .map_err(|e| TryFromProtoError::invalid(Object::PREVIOUS_TRANSACTION_FIELD, e))?;
343 let storage_rebate = value
344 .storage_rebate
345 .ok_or_else(|| TryFromProtoError::missing("storage_rebate"))?;
346
347 let object_data = if value.object_type() == PACKAGE_TYPE {
348 sui_sdk_types::ObjectData::Package(try_extract_package(value)?)
350 } else {
351 sui_sdk_types::ObjectData::Struct(try_extract_struct(value)?)
353 };
354
355 Ok(Self::new(
356 object_data,
357 owner,
358 previous_transaction,
359 storage_rebate,
360 ))
361 }
362}
363
364impl From<sui_sdk_types::TypeOrigin> for TypeOrigin {
369 fn from(value: sui_sdk_types::TypeOrigin) -> Self {
370 Self {
371 module_name: Some(value.module_name.to_string()),
372 datatype_name: Some(value.struct_name.to_string()),
373 package_id: Some(value.package.to_string()),
374 }
375 }
376}
377
378impl TryFrom<&TypeOrigin> for sui_sdk_types::TypeOrigin {
379 type Error = TryFromProtoError;
380
381 fn try_from(value: &TypeOrigin) -> Result<Self, Self::Error> {
382 let module_name = value
383 .module_name
384 .as_ref()
385 .ok_or_else(|| TryFromProtoError::missing("module_name"))?
386 .parse()
387 .map_err(|e| TryFromProtoError::invalid(TypeOrigin::MODULE_NAME_FIELD, e))?;
388
389 let struct_name = value
390 .datatype_name
391 .as_ref()
392 .ok_or_else(|| TryFromProtoError::missing("datatype_name"))?
393 .parse()
394 .map_err(|e| TryFromProtoError::invalid(TypeOrigin::DATATYPE_NAME_FIELD, e))?;
395
396 let package = value
397 .package_id
398 .as_ref()
399 .ok_or_else(|| TryFromProtoError::missing("package_id"))?
400 .parse()
401 .map_err(|e| TryFromProtoError::invalid(TypeOrigin::PACKAGE_ID_FIELD, e))?;
402
403 Ok(Self {
404 module_name,
405 struct_name,
406 package,
407 })
408 }
409}
410
411impl From<sui_sdk_types::GenesisObject> for Object {
416 fn from(value: sui_sdk_types::GenesisObject) -> Self {
417 let mut message = Self {
418 object_id: Some(value.object_id().to_string()),
419 version: Some(value.version()),
420 owner: Some(value.owner().to_owned().into()),
421 ..Default::default()
422 };
423
424 match value.data() {
425 sui_sdk_types::ObjectData::Struct(move_struct) => {
426 message.merge(move_struct, &FieldMaskTree::new_wildcard());
427 }
428 sui_sdk_types::ObjectData::Package(move_package) => {
429 message.merge(move_package, &FieldMaskTree::new_wildcard());
430 }
431 }
432
433 message
434 }
435}
436
437impl TryFrom<&Object> for sui_sdk_types::GenesisObject {
438 type Error = TryFromProtoError;
439
440 fn try_from(value: &Object) -> Result<Self, Self::Error> {
441 let object_data = if value.object_type() == PACKAGE_TYPE {
442 sui_sdk_types::ObjectData::Package(try_extract_package(value)?)
444 } else {
445 sui_sdk_types::ObjectData::Struct(try_extract_struct(value)?)
447 };
448
449 let owner = value
450 .owner
451 .as_ref()
452 .ok_or_else(|| TryFromProtoError::missing("owner"))?
453 .try_into()?;
454
455 Ok(Self::new(object_data, owner))
456 }
457}
458
459impl Object {
460 pub fn object_reference(&self) -> ObjectReference {
461 ObjectReference {
462 object_id: self.object_id.clone(),
463 version: self.version,
464 digest: self.digest.clone(),
465 }
466 }
467}
468
469impl From<sui_sdk_types::ObjectReference> for ObjectReference {
474 fn from(value: sui_sdk_types::ObjectReference) -> Self {
475 let (object_id, version, digest) = value.into_parts();
476 Self {
477 object_id: Some(object_id.to_string()),
478 version: Some(version),
479 digest: Some(digest.to_string()),
480 }
481 }
482}
483
484impl TryFrom<&ObjectReference> for sui_sdk_types::ObjectReference {
485 type Error = TryFromProtoError;
486
487 fn try_from(value: &ObjectReference) -> Result<Self, Self::Error> {
488 let object_id = value
489 .object_id
490 .as_ref()
491 .ok_or_else(|| TryFromProtoError::missing("object_id"))?
492 .parse()
493 .map_err(|e| TryFromProtoError::invalid(ObjectReference::OBJECT_ID_FIELD, e))?;
494
495 let version = value
496 .version
497 .ok_or_else(|| TryFromProtoError::missing("version"))?;
498
499 let digest = value
500 .digest
501 .as_ref()
502 .ok_or_else(|| TryFromProtoError::missing("digest"))?
503 .parse()
504 .map_err(|e| TryFromProtoError::invalid(ObjectReference::DIGEST_FIELD, e))?;
505
506 Ok(Self::new(object_id, version, digest))
507 }
508}
509
510impl From<sui_sdk_types::Owner> for Owner {
515 fn from(value: sui_sdk_types::Owner) -> Self {
516 use owner::OwnerKind;
517 use sui_sdk_types::Owner::*;
518
519 let mut message = Self::default();
520
521 let kind = match value {
522 Address(address) => {
523 message.address = Some(address.to_string());
524 OwnerKind::Address
525 }
526 Object(object) => {
527 message.address = Some(object.to_string());
528 OwnerKind::Object
529 }
530 Shared(version) => {
531 message.version = Some(version);
532 OwnerKind::Shared
533 }
534 Immutable => OwnerKind::Immutable,
535 ConsensusAddress {
536 start_version,
537 owner,
538 } => {
539 message.version = Some(start_version);
540 message.address = Some(owner.to_string());
541 OwnerKind::ConsensusAddress
542 }
543 _ => OwnerKind::Unknown,
544 };
545
546 message.set_kind(kind);
547 message
548 }
549}
550
551impl TryFrom<&Owner> for sui_sdk_types::Owner {
552 type Error = TryFromProtoError;
553
554 fn try_from(value: &Owner) -> Result<Self, Self::Error> {
555 use owner::OwnerKind;
556
557 match value.kind() {
558 OwnerKind::Unknown => {
559 return Err(TryFromProtoError::invalid(
560 Owner::KIND_FIELD,
561 "unknown OwnerKind",
562 ));
563 }
564 OwnerKind::Address => Self::Address(
565 value
566 .address()
567 .parse()
568 .map_err(|e| TryFromProtoError::invalid(Owner::ADDRESS_FIELD, e))?,
569 ),
570 OwnerKind::Object => Self::Object(
571 value
572 .address()
573 .parse()
574 .map_err(|e| TryFromProtoError::invalid(Owner::ADDRESS_FIELD, e))?,
575 ),
576 OwnerKind::Shared => Self::Shared(value.version()),
577 OwnerKind::Immutable => Self::Immutable,
578 OwnerKind::ConsensusAddress => Self::ConsensusAddress {
579 start_version: value.version(),
580 owner: value
581 .address()
582 .parse()
583 .map_err(|e| TryFromProtoError::invalid(Owner::ADDRESS_FIELD, e))?,
584 },
585 }
586 .pipe(Ok)
587 }
588}
589
590impl Merge<&ObjectSet> for ObjectSet {
591 fn merge(&mut self, source: &ObjectSet, mask: &FieldMaskTree) {
592 if let Some(submask) = mask.subtree(Self::OBJECTS_FIELD) {
593 self.objects = source
594 .objects()
595 .iter()
596 .map(|object| Object::merge_from(object, &submask))
597 .collect();
598 }
599 }
600}
601
602impl ObjectSet {
603 #[doc(hidden)]
605 pub fn sort_objects(&mut self) {
606 self.objects_mut().sort_by(|a, b| {
607 let a = (a.object_id(), a.version());
608 let b = (b.object_id(), b.version());
609 a.cmp(&b)
610 });
611 }
612
613 pub fn binary_search<'a>(
617 &'a self,
618 object_id: &sui_sdk_types::Address,
619 version: u64,
620 ) -> Option<&'a Object> {
621 let object_id = object_id.to_string();
622 let seek = (object_id.as_str(), version);
623 self.objects()
624 .binary_search_by(|object| {
625 let probe = (object.object_id(), object.version());
626 probe.cmp(&seek)
627 })
628 .ok()
629 .and_then(|found| self.objects().get(found))
630 }
631}