1pub mod account_root;
2pub mod current_escrow;
3pub mod escrow;
4pub mod traits;
5
6use crate::core::types::account_id::{ACCOUNT_ID_SIZE, AccountID};
7use crate::core::types::amount::{AMOUNT_SIZE, Amount};
8use crate::core::types::blob::Blob;
9use crate::core::types::currency::{CURRENCY_SIZE, Currency};
10use crate::core::types::issue::Issue;
11use crate::core::types::uint::{HASH128_SIZE, HASH256_SIZE, Hash128, Hash256};
12use crate::host::error_codes::{
13 match_result_code_with_expected_bytes, match_result_code_with_expected_bytes_optional,
14};
15use crate::host::field_helpers::{
16 get_fixed_size_field_with_expected_bytes, get_fixed_size_field_with_expected_bytes_optional,
17 get_variable_size_field, get_variable_size_field_optional,
18};
19use crate::host::{Result, get_current_ledger_obj_field, get_ledger_obj_field};
20
21pub trait FieldGetter: Sized {
68 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self>;
80
81 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>>;
94
95 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self>;
108
109 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>>;
123}
124
125trait FixedSizeFieldType: Sized {
138 const SIZE: usize;
140}
141
142impl FixedSizeFieldType for u8 {
143 const SIZE: usize = 1;
144}
145
146impl FixedSizeFieldType for u16 {
147 const SIZE: usize = 2;
148}
149
150impl FixedSizeFieldType for u32 {
151 const SIZE: usize = 4;
152}
153
154impl FixedSizeFieldType for u64 {
155 const SIZE: usize = 8;
156}
157
158impl<T: FixedSizeFieldType> FieldGetter for T {
172 #[inline]
173 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
174 let mut value = core::mem::MaybeUninit::<T>::uninit();
175 let result_code =
176 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
177 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
178 value.assume_init()
179 })
180 }
181
182 #[inline]
183 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
184 let mut value = core::mem::MaybeUninit::<T>::uninit();
185 let result_code =
186 unsafe { get_current_ledger_obj_field(field_code, value.as_mut_ptr().cast(), T::SIZE) };
187 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
188 Some(unsafe { value.assume_init() })
189 })
190 }
191
192 #[inline]
193 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
194 let mut value = core::mem::MaybeUninit::<T>::uninit();
195 let result_code = unsafe {
196 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
197 };
198 match_result_code_with_expected_bytes(result_code, T::SIZE, || unsafe {
199 value.assume_init()
200 })
201 }
202
203 #[inline]
204 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
205 let mut value = core::mem::MaybeUninit::<T>::uninit();
206 let result_code = unsafe {
207 get_ledger_obj_field(register_num, field_code, value.as_mut_ptr().cast(), T::SIZE)
208 };
209 match_result_code_with_expected_bytes_optional(result_code, T::SIZE, || {
210 Some(unsafe { value.assume_init() })
211 })
212 }
213}
214
215impl FieldGetter for AccountID {
227 #[inline]
228 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
229 match get_fixed_size_field_with_expected_bytes::<ACCOUNT_ID_SIZE, _>(
230 field_code,
231 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
232 ) {
233 Result::Ok(buffer) => Result::Ok(buffer.into()),
234 Result::Err(e) => Result::Err(e),
235 }
236 }
237
238 #[inline]
239 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
240 match get_fixed_size_field_with_expected_bytes_optional::<ACCOUNT_ID_SIZE, _>(
241 field_code,
242 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
243 ) {
244 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
245 Result::Err(e) => Result::Err(e),
246 }
247 }
248
249 #[inline]
250 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
251 match get_fixed_size_field_with_expected_bytes::<ACCOUNT_ID_SIZE, _>(
252 field_code,
253 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
254 ) {
255 Result::Ok(buffer) => Result::Ok(buffer.into()),
256 Result::Err(e) => Result::Err(e),
257 }
258 }
259
260 #[inline]
261 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
262 match get_fixed_size_field_with_expected_bytes_optional::<ACCOUNT_ID_SIZE, _>(
263 field_code,
264 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
265 ) {
266 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
267 Result::Err(e) => Result::Err(e),
268 }
269 }
270}
271
272impl FieldGetter for Amount {
284 #[inline]
285 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
286 match get_variable_size_field::<AMOUNT_SIZE, _>(field_code, |fc, buf, size| unsafe {
287 get_current_ledger_obj_field(fc, buf, size)
288 }) {
289 Result::Ok((buffer, _len)) => Result::Ok(Amount::from(buffer)),
290 Result::Err(e) => Result::Err(e),
291 }
292 }
293
294 #[inline]
295 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
296 match get_variable_size_field_optional::<AMOUNT_SIZE, _>(
297 field_code,
298 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
299 ) {
300 Result::Ok(opt) => Result::Ok(opt.map(|(buffer, _len)| Amount::from(buffer))),
301 Result::Err(e) => Result::Err(e),
302 }
303 }
304
305 #[inline]
306 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
307 match get_variable_size_field::<AMOUNT_SIZE, _>(field_code, |fc, buf, size| unsafe {
308 get_ledger_obj_field(register_num, fc, buf, size)
309 }) {
310 Result::Ok((buffer, _len)) => Result::Ok(Amount::from(buffer)),
311 Result::Err(e) => Result::Err(e),
312 }
313 }
314
315 #[inline]
316 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
317 match get_variable_size_field_optional::<AMOUNT_SIZE, _>(
318 field_code,
319 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
320 ) {
321 Result::Ok(opt) => Result::Ok(opt.map(|(buffer, _len)| Amount::from(buffer))),
322 Result::Err(e) => Result::Err(e),
323 }
324 }
325}
326
327impl FieldGetter for Hash128 {
338 #[inline]
339 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
340 match get_fixed_size_field_with_expected_bytes::<HASH128_SIZE, _>(
341 field_code,
342 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
343 ) {
344 Result::Ok(buffer) => Result::Ok(buffer.into()),
345 Result::Err(e) => Result::Err(e),
346 }
347 }
348
349 #[inline]
350 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
351 match get_fixed_size_field_with_expected_bytes_optional::<HASH128_SIZE, _>(
352 field_code,
353 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
354 ) {
355 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
356 Result::Err(e) => Result::Err(e),
357 }
358 }
359
360 #[inline]
361 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
362 match get_fixed_size_field_with_expected_bytes::<HASH128_SIZE, _>(
363 field_code,
364 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
365 ) {
366 Result::Ok(buffer) => Result::Ok(buffer.into()),
367 Result::Err(e) => Result::Err(e),
368 }
369 }
370
371 #[inline]
372 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
373 match get_fixed_size_field_with_expected_bytes_optional::<HASH128_SIZE, _>(
374 field_code,
375 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
376 ) {
377 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
378 Result::Err(e) => Result::Err(e),
379 }
380 }
381}
382
383impl FieldGetter for Hash256 {
394 #[inline]
395 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
396 match get_fixed_size_field_with_expected_bytes::<HASH256_SIZE, _>(
397 field_code,
398 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
399 ) {
400 Result::Ok(buffer) => Result::Ok(buffer.into()),
401 Result::Err(e) => Result::Err(e),
402 }
403 }
404
405 #[inline]
406 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
407 match get_fixed_size_field_with_expected_bytes_optional::<HASH256_SIZE, _>(
408 field_code,
409 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
410 ) {
411 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
412 Result::Err(e) => Result::Err(e),
413 }
414 }
415
416 #[inline]
417 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
418 match get_fixed_size_field_with_expected_bytes::<HASH256_SIZE, _>(
419 field_code,
420 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
421 ) {
422 Result::Ok(buffer) => Result::Ok(buffer.into()),
423 Result::Err(e) => Result::Err(e),
424 }
425 }
426
427 #[inline]
428 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
429 match get_fixed_size_field_with_expected_bytes_optional::<HASH256_SIZE, _>(
430 field_code,
431 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
432 ) {
433 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
434 Result::Err(e) => Result::Err(e),
435 }
436 }
437}
438
439impl<const N: usize> FieldGetter for Blob<N> {
456 #[inline]
457 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
458 match get_variable_size_field::<N, _>(field_code, |fc, buf, size| unsafe {
459 get_current_ledger_obj_field(fc, buf, size)
460 }) {
461 Result::Ok((data, len)) => Result::Ok(Blob { data, len }),
462 Result::Err(e) => Result::Err(e),
463 }
464 }
465
466 #[inline]
467 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
468 match get_variable_size_field_optional::<N, _>(field_code, |fc, buf, size| unsafe {
469 get_current_ledger_obj_field(fc, buf, size)
470 }) {
471 Result::Ok(opt) => Result::Ok(opt.map(|(data, len)| Blob { data, len })),
472 Result::Err(e) => Result::Err(e),
473 }
474 }
475
476 #[inline]
477 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
478 match get_variable_size_field::<N, _>(field_code, |fc, buf, size| unsafe {
479 get_ledger_obj_field(register_num, fc, buf, size)
480 }) {
481 Result::Ok((data, len)) => Result::Ok(Blob { data, len }),
482 Result::Err(e) => Result::Err(e),
483 }
484 }
485
486 #[inline]
487 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
488 match get_variable_size_field_optional::<N, _>(field_code, |fc, buf, size| unsafe {
489 get_ledger_obj_field(register_num, fc, buf, size)
490 }) {
491 Result::Ok(opt) => Result::Ok(opt.map(|(data, len)| Blob { data, len })),
492 Result::Err(e) => Result::Err(e),
493 }
494 }
495}
496
497impl FieldGetter for Currency {
507 #[inline]
508 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
509 match get_fixed_size_field_with_expected_bytes::<CURRENCY_SIZE, _>(
510 field_code,
511 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
512 ) {
513 Result::Ok(buffer) => Result::Ok(buffer.into()),
514 Result::Err(e) => Result::Err(e),
515 }
516 }
517
518 #[inline]
519 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
520 match get_fixed_size_field_with_expected_bytes_optional::<CURRENCY_SIZE, _>(
521 field_code,
522 |fc, buf, size| unsafe { get_current_ledger_obj_field(fc, buf, size) },
523 ) {
524 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
525 Result::Err(e) => Result::Err(e),
526 }
527 }
528
529 #[inline]
530 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
531 match get_fixed_size_field_with_expected_bytes::<CURRENCY_SIZE, _>(
532 field_code,
533 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
534 ) {
535 Result::Ok(buffer) => Result::Ok(buffer.into()),
536 Result::Err(e) => Result::Err(e),
537 }
538 }
539
540 #[inline]
541 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
542 match get_fixed_size_field_with_expected_bytes_optional::<CURRENCY_SIZE, _>(
543 field_code,
544 |fc, buf, size| unsafe { get_ledger_obj_field(register_num, fc, buf, size) },
545 ) {
546 Result::Ok(buffer) => Result::Ok(buffer.map(|b| b.into())),
547 Result::Err(e) => Result::Err(e),
548 }
549 }
550}
551
552impl FieldGetter for Issue {
567 #[inline]
568 fn get_from_current_ledger_obj(field_code: i32) -> Result<Self> {
569 match get_variable_size_field::<40, _>(field_code, |fc, buf, size| unsafe {
570 get_current_ledger_obj_field(fc, buf, size)
571 }) {
572 Result::Ok((buffer, len)) => Issue::from_buffer(buffer, len),
573 Result::Err(e) => Result::Err(e),
574 }
575 }
576
577 #[inline]
578 fn get_from_current_ledger_obj_optional(field_code: i32) -> Result<Option<Self>> {
579 match get_variable_size_field_optional::<40, _>(field_code, |fc, buf, size| unsafe {
580 get_current_ledger_obj_field(fc, buf, size)
581 }) {
582 Result::Ok(Some((buffer, len))) => match Issue::from_buffer(buffer, len) {
583 Result::Ok(issue) => Result::Ok(Some(issue)),
584 Result::Err(e) => Result::Err(e),
585 },
586 Result::Ok(None) => Result::Ok(None),
587 Result::Err(e) => Result::Err(e),
588 }
589 }
590
591 #[inline]
592 fn get_from_ledger_obj(register_num: i32, field_code: i32) -> Result<Self> {
593 match get_variable_size_field::<40, _>(field_code, |fc, buf, size| unsafe {
594 get_ledger_obj_field(register_num, fc, buf, size)
595 }) {
596 Result::Ok((buffer, len)) => Issue::from_buffer(buffer, len),
597 Result::Err(e) => Result::Err(e),
598 }
599 }
600
601 #[inline]
602 fn get_from_ledger_obj_optional(register_num: i32, field_code: i32) -> Result<Option<Self>> {
603 match get_variable_size_field_optional::<40, _>(field_code, |fc, buf, size| unsafe {
604 get_ledger_obj_field(register_num, fc, buf, size)
605 }) {
606 Result::Ok(Some((buffer, len))) => match Issue::from_buffer(buffer, len) {
607 Result::Ok(issue) => Result::Ok(Some(issue)),
608 Result::Err(e) => Result::Err(e),
609 },
610 Result::Ok(None) => Result::Ok(None),
611 Result::Err(e) => Result::Err(e),
612 }
613 }
614}
615
616pub mod current_ledger_object {
617 use super::FieldGetter;
618 use crate::host::Result;
619
620 #[inline]
632 pub fn get_field<T: FieldGetter>(field_code: i32) -> Result<T> {
633 T::get_from_current_ledger_obj(field_code)
634 }
635
636 #[inline]
649 pub fn get_field_optional<T: FieldGetter>(field_code: i32) -> Result<Option<T>> {
650 T::get_from_current_ledger_obj_optional(field_code)
651 }
652}
653
654pub mod ledger_object {
655 use super::FieldGetter;
656 use crate::host::Result;
657
658 #[inline]
671 pub fn get_field<T: FieldGetter>(register_num: i32, field_code: i32) -> Result<T> {
672 T::get_from_ledger_obj(register_num, field_code)
673 }
674
675 #[inline]
689 pub fn get_field_optional<T: FieldGetter>(
690 register_num: i32,
691 field_code: i32,
692 ) -> Result<Option<T>> {
693 T::get_from_ledger_obj_optional(register_num, field_code)
694 }
695
696 #[cfg(test)]
697 mod tests {
698 use super::*;
699 use crate::core::ledger_objects::{current_ledger_object, ledger_object};
700 use crate::core::types::account_id::{ACCOUNT_ID_SIZE, AccountID};
701 use crate::core::types::amount::Amount;
702 use crate::core::types::blob::{Blob, DEFAULT_BLOB_SIZE};
703 use crate::core::types::public_key::PUBLIC_KEY_BUFFER_SIZE;
704 use crate::core::types::uint::{HASH128_SIZE, HASH256_SIZE, Hash128, Hash256};
705 use crate::sfield;
706
707 #[test]
714 fn test_field_getter_basic_types() {
715 assert!(u16::get_from_current_ledger_obj(sfield::LedgerEntryType).is_ok());
717 assert!(u32::get_from_current_ledger_obj(sfield::Flags).is_ok());
718 assert!(u64::get_from_current_ledger_obj(sfield::Balance).is_ok());
719 }
720
721 #[test]
722 fn test_field_getter_xrpl_types() {
723 assert!(AccountID::get_from_current_ledger_obj(sfield::Account).is_ok());
725 assert!(Amount::get_from_current_ledger_obj(sfield::Amount).is_ok());
726 assert!(Hash128::get_from_current_ledger_obj(sfield::EmailHash).is_ok());
727 assert!(Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID).is_ok());
728
729 let blob: Blob<DEFAULT_BLOB_SIZE> =
730 Blob::get_from_current_ledger_obj(sfield::PublicKey).unwrap();
731 assert_eq!(blob.len, DEFAULT_BLOB_SIZE);
733 }
734
735 #[test]
736 fn test_field_getter_optional_variants() {
737 let result = u32::get_from_current_ledger_obj_optional(sfield::Flags);
739 assert!(result.is_ok());
740 assert!(result.unwrap().is_some());
741
742 let result = AccountID::get_from_current_ledger_obj_optional(sfield::Account);
743 assert!(result.is_ok());
744 assert!(result.unwrap().is_some());
745 }
746
747 #[test]
748 fn test_field_getter_with_slot() {
749 let slot = 0;
751 assert!(u32::get_from_ledger_obj(slot, sfield::Flags).is_ok());
752 assert!(u64::get_from_ledger_obj(slot, sfield::Balance).is_ok());
753 assert!(AccountID::get_from_ledger_obj(slot, sfield::Account).is_ok());
754 }
755
756 #[test]
757 fn test_field_getter_optional_with_slot() {
758 let slot = 0;
760 let result = u32::get_from_ledger_obj_optional(slot, sfield::Flags);
761 assert!(result.is_ok());
762 assert!(result.unwrap().is_some());
763 }
764
765 #[test]
770 fn test_current_ledger_object_module() {
771 assert!(current_ledger_object::get_field::<u32>(sfield::Flags).is_ok());
773 assert!(current_ledger_object::get_field::<AccountID>(sfield::Account).is_ok());
774
775 let result = current_ledger_object::get_field_optional::<u32>(sfield::Flags);
776 assert!(result.is_ok());
777 assert!(result.unwrap().is_some());
778 }
779
780 #[test]
781 fn test_ledger_object_module() {
782 let slot = 0;
784 assert!(ledger_object::get_field::<u16>(slot, sfield::LedgerEntryType).is_ok());
785 assert!(ledger_object::get_field::<u32>(slot, sfield::Flags).is_ok());
786 assert!(ledger_object::get_field::<u64>(slot, sfield::Balance).is_ok());
787 assert!(ledger_object::get_field::<AccountID>(slot, sfield::Account).is_ok());
788 assert!(ledger_object::get_field::<Amount>(slot, sfield::Amount).is_ok());
789 assert!(ledger_object::get_field::<Hash128>(slot, sfield::EmailHash).is_ok());
790 assert!(ledger_object::get_field::<Hash256>(slot, sfield::PreviousTxnID).is_ok());
791 assert!(ledger_object::get_field::<Blob<33>>(slot, sfield::PublicKey).is_ok());
792
793 let result = ledger_object::get_field_optional::<u32>(slot, sfield::Flags);
794 assert!(result.is_ok());
795 assert!(result.unwrap().is_some());
796 }
797
798 #[test]
803 fn test_type_inference() {
804 let slot = 0;
805 let _balance = get_field::<u64>(slot, sfield::Balance);
807 let _account = get_field::<AccountID>(slot, sfield::Account);
808
809 let _sequence: Result<u32> = get_field(slot, sfield::Sequence);
811 let _flags: Result<u32> = get_field(slot, sfield::Flags);
812 }
813
814 #[test]
819 fn test_type_sizes() {
820 let hash128 = Hash128::get_from_current_ledger_obj(sfield::EmailHash).unwrap();
822 assert_eq!(hash128.as_bytes().len(), HASH128_SIZE);
823
824 let hash256 = Hash256::get_from_current_ledger_obj(sfield::PreviousTxnID).unwrap();
825 assert_eq!(hash256.as_bytes().len(), HASH256_SIZE);
826
827 let account = AccountID::get_from_current_ledger_obj(sfield::Account).unwrap();
828 assert_eq!(account.0.len(), ACCOUNT_ID_SIZE);
829
830 let blob: Blob<{ PUBLIC_KEY_BUFFER_SIZE }> =
831 Blob::get_from_current_ledger_obj(sfield::PublicKey).unwrap();
832 assert_eq!(blob.len, PUBLIC_KEY_BUFFER_SIZE);
834 assert_eq!(blob.data.len(), PUBLIC_KEY_BUFFER_SIZE);
835 }
836 }
837}