servio_service/
lib.rs

1#![forbid(unsafe_code)]
2
3use futures_core::Stream;
4use std::any::{Any, TypeId};
5use std::borrow::Cow;
6use std::collections::HashMap;
7use std::future::Future;
8use std::hash::{BuildHasherDefault, Hasher};
9use std::ops::DerefMut;
10use std::sync::Arc;
11
12/// Request metadata, containing protocol identifier and a set of scopes, identified by type.
13///
14/// It works like a TypeMap with a tag. A typical way to use the scope is to match protocol
15/// identifier by value and get one or multiple scopes.
16/// `Scope` is itself protocol-independent with protocol identifiers and scope types provided in
17/// other crates. For example, HTTP and WebSocket are defined in servio-http crate.
18///
19/// ASGI equivalent: [Connection Scope](https://asgi.readthedocs.io/en/latest/specs/main.html#connection-scope)
20#[derive(Clone, Debug)]
21pub struct Scope {
22    protocol: Cow<'static, str>,
23    scopes: HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<TypeIdHasher>>,
24}
25
26impl Scope {
27    /// Creates a new `Scope` with a specified protocol identifier.
28    #[inline]
29    pub fn new(protocol: Cow<'static, str>) -> Self {
30        Self {
31            protocol,
32            scopes: Default::default(),
33        }
34    }
35
36    /// Returns a protocol identifier of `Scope`.
37    #[inline]
38    pub fn protocol(&self) -> &str {
39        &self.protocol
40    }
41
42    /// Returns new `Scope` with specified prococol identifier, consuming surrent `Scope`.
43    #[inline]
44    pub fn with_protocol(self, protocol: Cow<'static, str>) -> Self {
45        Self {
46            protocol,
47            scopes: self.scopes,
48        }
49    }
50
51    /// Returns reference-counted scope of provided type.
52    /// This scope can be saved by middleware for internal use.
53    #[inline]
54    pub fn get<T: Any + Sync + Send>(&self) -> Option<Arc<T>> {
55        self.scopes
56            .get(&TypeId::of::<T>())?
57            .clone()
58            .downcast::<T>()
59            .ok()
60    }
61
62    /// Returns reference to scope of provided type.
63    #[inline]
64    pub fn get_ref<T: Any + Sync + Send>(&self) -> Option<&T> {
65        self.scopes.get(&TypeId::of::<T>())?.downcast_ref::<T>()
66    }
67
68    /// Inserts a scope of specified type into `Scope`.
69    #[inline]
70    pub fn insert<T: Any + Sync + Send>(&mut self, scope: T) -> Option<Arc<T>> {
71        self.scopes
72            .insert(TypeId::of::<T>(), Arc::new(scope))
73            .map(|arc| arc.downcast::<T>().unwrap())
74    }
75
76    /// Removes a scope of specified type from `Scope`.
77    /// This may be useful in middlewares, that change protocol identifier or in inter-middleware
78    /// communication.
79    #[inline]
80    pub fn remove<T: Any + Sync + Send>(&mut self) -> Option<Arc<T>> {
81        self.scopes
82            .remove(&TypeId::of::<T>())
83            .map(|arc| arc.downcast::<T>().unwrap())
84    }
85
86    /// Consumes `self` and returns new `Scope` with scope inserted in internal map.
87    #[inline]
88    pub fn with_scope<T: Any + Sync + Send>(mut self, scope: T) -> Self {
89        let _ = self.insert(scope);
90        self
91    }
92}
93
94/// Structure for representing an event, that is sent or received over Server- and AppStreams.
95/// Event contains family, that could be used for matching inside servers, apps and middlewares.
96///
97/// ASGI equivalent: [Event](https://asgi.readthedocs.io/en/latest/specs/main.html#events)
98#[derive(Clone, Debug)]
99pub struct Event {
100    family: Cow<'static, str>,
101    event: Arc<dyn Any + Sync + Send>,
102}
103
104impl Event {
105    /// Creates new event of specified family and type.
106    #[inline]
107    pub fn new<T: Any + Sync + Send>(family: Cow<'static, str>, event: T) -> Self {
108        Self {
109            family,
110            event: Arc::new(event),
111        }
112    }
113
114    /// Returns event family.
115    #[inline]
116    pub fn family(&self) -> &str {
117        &self.family
118    }
119
120    /// Returns reference-counted event of concrete type.
121    #[inline]
122    pub fn get<T: Any + Sync + Send>(&self) -> Option<Arc<T>> {
123        self.event.clone().downcast::<T>().ok()
124    }
125
126    /// Returns reference event of concrete type
127    #[inline]
128    pub fn get_ref<T: Any + Sync + Send>(&self) -> Option<&T> {
129        self.event.downcast_ref::<T>()
130    }
131}
132
133/// Trait, representing a Service, that is used to handle connections.
134///
135/// It can handle multiple connections at simultaneously.
136///
137/// ASGI equivalent: [Application](https://asgi.readthedocs.io/en/latest/specs/main.html#applications)
138pub trait Service<ServerStream: Stream<Item = Event>> {
139    type AppStream: Stream<Item = Event>;
140    type Error: std::error::Error;
141    type Future: Future<Output = Result<Self::AppStream, Self::Error>>;
142
143    /// Main function of a service.
144    fn call(&mut self, scope: Scope, server_events: ServerStream) -> Self::Future;
145}
146
147#[derive(Default)]
148struct TypeIdHasher {
149    value: u64,
150}
151
152impl Hasher for TypeIdHasher {
153    #[inline]
154    fn finish(&self) -> u64 {
155        self.value
156    }
157
158    #[inline]
159    fn write(&mut self, bytes: &[u8]) {
160        debug_assert_eq!(bytes.len(), 8);
161        let _ = bytes
162            .try_into()
163            .map(|array| self.value = u64::from_ne_bytes(array));
164    }
165}
166
167impl<X, S, SS> Service<SS> for X
168where
169    X: DerefMut<Target = S>,
170    S: Service<SS>,
171    SS: Stream<Item = Event>,
172{
173    type AppStream = S::AppStream;
174    type Error = S::Error;
175    type Future = S::Future;
176
177    fn call(&mut self, scope: Scope, server_events: SS) -> Self::Future {
178        (**self).call(scope, server_events)
179    }
180}