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