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
use std::sync::Arc;

use seeded_random::{Random, Seed};
use serde::de::DeserializeOwned;
use serde::Serialize;
use wick_packet::{date_from_millis, ContextTransport, DateTime, InherentData};

#[cfg(target_family = "wasm")]
/// A conditional trait that implements Send if the target is not wasm.
pub trait LocalAwareSend {}
#[cfg(not(target_family = "wasm"))]
/// A conditional trait that implements Send if the target is not wasm.
pub trait LocalAwareSend: Send {}

#[cfg(target_family = "wasm")]
impl<T> LocalAwareSend for T {}

#[cfg(not(target_family = "wasm"))]
impl<T> LocalAwareSend for T where T: Send {}

#[derive(Clone)]
#[non_exhaustive]
/// A context that is passed to a component's operations.
pub struct Context<T>
where
  T: std::fmt::Debug,
  T: LocalAwareSend,
{
  /// Operation-specific configuration.
  pub config: Arc<T>,
  /// Inherent data passed to the operation.
  pub inherent: InherentContext,
  #[cfg(feature = "invocation")]
  /// A callback to invoke other components within the executing runtime.
  pub callback: Arc<crate::RuntimeCallback>,
}

impl<T> std::fmt::Debug for Context<T>
where
  T: std::fmt::Debug + DeserializeOwned + Serialize,
  T: LocalAwareSend,
{
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("Context").field("config", &self.config).finish()
  }
}

impl<T> From<ContextTransport<T>> for Context<T>
where
  T: std::fmt::Debug + Serialize + DeserializeOwned,
  T: LocalAwareSend,
{
  fn from(value: ContextTransport<T>) -> Self {
    Self {
      inherent: InherentContext {
        rng: Random::from_seed(Seed::unsafe_new(value.inherent.seed)),
        timestamp: date_from_millis(value.inherent.timestamp).unwrap(),
      },
      config: Arc::new(value.config),
      #[cfg(feature = "invocation")]
      callback: crate::panic_callback(),
    }
  }
}

#[derive(Debug)]
#[non_exhaustive]
/// Inherent data passed to an operation.
pub struct InherentContext {
  /// A random number generator initialized from the invocation seed.
  pub rng: Random,
  /// The timestamp of the invocation.
  pub timestamp: DateTime,
}

impl Clone for InherentContext {
  fn clone(&self) -> Self {
    Self {
      rng: Random::from_seed(self.rng.seed()),
      timestamp: self.timestamp,
    }
  }
}

impl From<InherentContext> for InherentData {
  fn from(value: InherentContext) -> Self {
    Self::new(value.rng.gen(), value.timestamp.timestamp_millis() as _)
  }
}

impl From<InherentData> for InherentContext {
  fn from(value: InherentData) -> Self {
    Self {
      rng: Random::from_seed(Seed::unsafe_new(value.seed)),
      timestamp: date_from_millis(value.timestamp).unwrap(),
    }
  }
}

impl<T> Context<T>
where
  T: std::fmt::Debug,
  T: LocalAwareSend,
{
  /// Create a new context.
  #[cfg(feature = "invocation")]
  pub fn new(config: T, inherent: &InherentData, callback: Arc<crate::RuntimeCallback>) -> Self {
    Self {
      inherent: InherentContext {
        rng: Random::from_seed(Seed::unsafe_new(inherent.seed)),
        timestamp: date_from_millis(inherent.timestamp).unwrap(),
      },
      config: Arc::new(config),
      callback,
    }
  }

  /// Create a new context.
  #[cfg(not(feature = "invocation"))]
  pub fn new(config: T, inherent: &InherentData) -> Self {
    Self {
      inherent: InherentContext {
        rng: Random::from_seed(Seed::unsafe_new(inherent.seed)),
        timestamp: date_from_millis(inherent.timestamp).unwrap(),
      },
      config: Arc::new(config),
    }
  }
}