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
use crate::type_registry::ShortTypeId;
use crate::actor_system::World;
use crate::actor::ActorOrActorTrait;

/// Represents an `ActorSystem` in a networking topology
#[cfg_attr(
    feature = "serde-serialization",
    derive(Serialize, Deserialize)
)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Debug)]
pub struct MachineID(pub u8);

/// A raw (untyped) ID referring to an actor class instance
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct RawID {
    /// instance ID within the class
    pub instance_id: u32,
    /// actual type of the instance (always points to a concrete class
    /// even if this `RawID` is contained in a `TypedID` representing
    /// an actor trait)
    pub type_id: ShortTypeId,
    /// The machine in the networking topology this instance lives on
    pub machine: MachineID,
    /// A version of the ID to be able to  safelyreuse instance IDs
    /// after an actor dies.
    pub version: u8,
}

pub fn broadcast_instance_id() -> u32 {
    u32::max_value()
}

pub fn broadcast_machine_id() -> MachineID {
    MachineID(u8::max_value())
}

impl RawID {
    /// Create a new RawID from its parts
    pub fn new(type_id: ShortTypeId, instance_id: u32, machine: MachineID, version: u8) -> Self {
        RawID {
            type_id,
            machine,
            version,
            instance_id,
        }
    }

    /// Convert a given RawID into one that represents a local broadcast
    pub fn local_broadcast(&self) -> RawID {
        RawID {
            instance_id: broadcast_instance_id(),
            ..*self
        }
    }

    /// Convert a given RawID into one that represents a global broadcast
    pub fn global_broadcast(&self) -> RawID {
        RawID {
            machine: broadcast_machine_id(),
            ..self.local_broadcast()
        }
    }

    /// Check whether this RawID represents a (local || global) broadcast
    pub fn is_broadcast(&self) -> bool {
        self.instance_id == broadcast_instance_id()
    }

    /// Check whether this RawID represents a global broadcast
    pub fn is_global_broadcast(&self) -> bool {
        self.machine == broadcast_machine_id()
    }

    /// Get the canonical string format of a RawID
    pub fn format(&self, world: &mut World) -> String {
        format!(
            "{}_{:X}.{:X}@{:X}",
            world.get_actor_name(self.type_id),
            self.instance_id,
            self.version,
            self.machine.0
        )
    }
}

impl ::std::fmt::Debug for RawID {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(
            f,
            "{:X}_{:X}.{:X}@{:X}",
            u16::from(self.type_id),
            self.instance_id,
            self.version,
            self.machine.0,
        )
    }
}

impl ::std::fmt::Display for RawID {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        ::std::fmt::Debug::fmt(self, f)
    }
}

#[derive(Debug)]
pub enum ParseRawIDError {
    Format,
    InvalidTypeId,
    ParseIntError(::std::num::ParseIntError),
}

impl ::std::fmt::Display for ParseRawIDError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        ::std::fmt::Debug::fmt(self, f)
    }
}

impl ::std::str::FromStr for RawID {
    type Err = ParseRawIDError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut parts = s.split(|c| c == '_' || c == '.' || c == '@');

        match (parts.next(), parts.next(), parts.next(), parts.next()) {
            (Some(type_part), Some(instance_part), Some(version_part), Some(machine_part)) => {
                let type_id = ShortTypeId::new(
                    u16::from_str_radix(type_part, 16).map_err(ParseRawIDError::ParseIntError)?,
                ).ok_or(ParseRawIDError::InvalidTypeId)?;
                let instance_id = u32::from_str_radix(instance_part, 16)
                    .map_err(ParseRawIDError::ParseIntError)?;
                let version =
                    u8::from_str_radix(version_part, 16).map_err(ParseRawIDError::ParseIntError)?;
                let machine = MachineID(
                    u8::from_str_radix(machine_part, 16).map_err(ParseRawIDError::ParseIntError)?,
                );
                Ok(RawID {
                    type_id,
                    machine,
                    version,
                    instance_id,
                })
            }
            _ => Err(ParseRawIDError::Format),
        }
    }
}

#[cfg(feature = "serde-serialization")]
use std::marker::PhantomData;

#[cfg(feature = "serde-serialization")]
impl ::serde::ser::Serialize for RawID {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ::serde::ser::Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(feature = "serde-serialization")]
struct RawIDVisitor {
    marker: PhantomData<fn() -> RawID>,
}

#[cfg(feature = "serde-serialization")]
impl RawIDVisitor {
    fn new() -> Self {
        RawIDVisitor {
            marker: PhantomData,
        }
    }
}

#[cfg(feature = "serde-serialization")]
impl<'de> ::serde::de::Visitor<'de> for RawIDVisitor {
    type Value = RawID;

    fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        formatter.write_str("A Raw Actor ID")
    }

    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
    where
        E: ::serde::de::Error,
    {
        s.parse().map_err(::serde::de::Error::custom)
    }
}

#[cfg(feature = "serde-serialization")]
impl<'de> ::serde::de::Deserialize<'de> for RawID {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: ::serde::de::Deserializer<'de>,
    {
        deserializer.deserialize_str(RawIDVisitor::new())
    }
}

/// Wraps a `RawID`, bringing type information regarding the referenced
/// actor class or trait to compile time, for type safe handling of ids.
pub trait TypedID: Copy + Clone + Sized + ::std::fmt::Debug + ::std::hash::Hash {
    /// The actor class or actor trait referenced by this ID type.
    type Target: ActorOrActorTrait;

    /// Get the wrapped RawID
    fn as_raw(&self) -> RawID;
    /// Get the canonical string representation of the wrapped RawID
    fn as_raw_string(&self) -> String {
        self.as_raw().to_string()
    }
    /// Create a `TypedID` based on a `RawID`. Note: this should only be done
    /// when you are sure that the `RawID` actually points at the correct actor
    /// class or trait at runtime
    fn from_raw(raw: RawID) -> Self;
    /// Create a `TypedID` based on the canoncial string representation of a `RawID`.
    /// Note: this should only be done
    /// when you are sure that the `RawID` actually points at the correct actor
    /// class or trait at runtime
    fn from_raw_str(raw_str: &str) -> Result<Self, ParseRawIDError> {
        Ok(Self::from_raw(raw_str.parse()?))
    }

    /// Get the local first actor instance of type `Target`
    fn local_first(world: &mut World) -> Self {
        Self::from_raw(world.local_first::<Self::Target>())
    }

    /// Get the global first actor instance of type `Target`
    fn global_first(world: &mut World) -> Self {
        Self::from_raw(world.global_first::<Self::Target>())
    }

    /// Get an ID representing a local broadcast to actors of type `Target`
    fn local_broadcast(world: &mut World) -> Self {
        Self::from_raw(world.local_broadcast::<Self::Target>())
    }

    /// Get an ID representing a global broadcast to actors of type `Target`
    fn global_broadcast(world: &mut World) -> Self {
        Self::from_raw(world.global_broadcast::<Self::Target>())
    }
}