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
use crate::blueprints::package::BlueprintVersion;
use crate::ScryptoSbor;
use core::fmt;
use core::fmt::Formatter;
use radix_engine_common::address::{AddressDisplayContext, NO_NETWORK};
use radix_engine_common::types::PackageAddress;
use radix_engine_common::types::{GenericSubstitution, GlobalAddress};
use radix_engine_derive::ManifestSbor;
use radix_engine_interface::api::AttachedModuleId;
use sbor::rust::prelude::*;
use scrypto_schema::KeyValueStoreGenericSubstitutions;
use utils::ContextualDisplay;

#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub enum OuterObjectInfo {
    Some { outer_object: GlobalAddress },
    None,
}

impl OuterObjectInfo {
    pub fn expect(&self) -> GlobalAddress {
        match self {
            OuterObjectInfo::Some { outer_object } => *outer_object,
            OuterObjectInfo::None => panic!("Object has no outer object"),
        }
    }
}

impl Default for OuterObjectInfo {
    fn default() -> Self {
        OuterObjectInfo::None
    }
}

/// Core object state, persisted in `TypeInfoSubstate`.
#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub struct BlueprintInfo {
    pub blueprint_id: BlueprintId,
    pub blueprint_version: BlueprintVersion,
    pub outer_obj_info: OuterObjectInfo,
    pub features: IndexSet<String>,
    pub generic_substitutions: Vec<GenericSubstitution>,
}

#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub enum ObjectType {
    Global {
        modules: IndexMap<AttachedModuleId, BlueprintVersion>,
    },
    Owned,
}

#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub struct ObjectInfo {
    /// Blueprint Info of Object
    pub blueprint_info: BlueprintInfo,
    pub object_type: ObjectType,
}

impl ObjectInfo {
    pub fn is_global(&self) -> bool {
        match self.object_type {
            ObjectType::Global { .. } => true,
            ObjectType::Owned => false,
        }
    }

    pub fn get_outer_object(&self) -> GlobalAddress {
        match &self.blueprint_info.outer_obj_info {
            OuterObjectInfo::Some { outer_object } => outer_object.clone(),
            OuterObjectInfo::None { .. } => {
                panic!("Broken Application logic: Expected to be an inner object but is an outer object");
            }
        }
    }

    pub fn get_features(&self) -> IndexSet<String> {
        self.blueprint_info.features.clone()
    }

    pub fn try_get_outer_object(&self) -> Option<GlobalAddress> {
        match &self.blueprint_info.outer_obj_info {
            OuterObjectInfo::Some { outer_object } => Some(outer_object.clone()),
            OuterObjectInfo::None { .. } => None,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub struct GlobalAddressPhantom {
    pub blueprint_id: BlueprintId,
}

#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
pub struct KeyValueStoreInfo {
    pub generic_substitutions: KeyValueStoreGenericSubstitutions,
}

#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, ScryptoSbor, ManifestSbor)]
pub struct BlueprintId {
    pub package_address: PackageAddress,
    pub blueprint_name: String,
}

impl BlueprintId {
    pub fn new<S: ToString>(package_address: &PackageAddress, blueprint_name: S) -> Self {
        BlueprintId {
            package_address: *package_address,
            blueprint_name: blueprint_name.to_string(),
        }
    }

    pub fn len(&self) -> usize {
        self.package_address.as_ref().len() + self.blueprint_name.len()
    }
}

impl<'a> ContextualDisplay<AddressDisplayContext<'a>> for BlueprintId {
    type Error = fmt::Error;

    fn contextual_format<F: fmt::Write>(
        &self,
        f: &mut F,
        context: &AddressDisplayContext<'a>,
    ) -> Result<(), Self::Error> {
        write!(
            f,
            "{}:<{}>",
            self.package_address.display(*context),
            self.blueprint_name,
        )
    }
}

impl core::fmt::Debug for BlueprintId {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.display(NO_NETWORK))
    }
}