gain/
origin.rs

1// Copyright (c) 2020 Timo Savola.
2// Use of this source code is governed by the MIT
3// license that can be found in the LICENSE file.
4
5//! Communicate with the invoker of the program instance.
6//!
7//! This can be thought of as standard I/O streams.
8
9use std::convert::TryInto;
10use std::fmt;
11
12use crate::service::Service;
13use crate::stream::RecvWriteStream;
14
15lazy_static! {
16    static ref SERVICE: Service = Service::register("origin");
17}
18
19/// Accept a new incoming connection.
20///
21/// The call is blocked while no connection is available, or the
22/// environment-dependent maximum number of simultaneous connections is
23/// reached.
24///
25/// Typically there is a correspondence between a connection and a program
26/// invocation or resumption.
27pub async fn accept() -> Result<RecvWriteStream, AcceptError> {
28    SERVICE
29        .call(&[], |reply: &[u8]| {
30            if reply.len() < 8 {
31                return Err(AcceptError::new(0));
32            }
33
34            let error = i16::from_le_bytes(reply[4..6].try_into().unwrap());
35            if error != 0 {
36                return Err(AcceptError::new(error));
37            }
38
39            Ok(SERVICE.stream(i32::from_le_bytes(reply[..4].try_into().unwrap())))
40        })
41        .await
42}
43
44/// Reason for connection acceptance failure.
45///
46/// No reasons have been defined yet.
47#[derive(Debug)]
48pub struct AcceptError {
49    code: i16,
50}
51
52impl AcceptError {
53    fn new(code: i16) -> Self {
54        Self { code }
55    }
56
57    pub fn as_i16(&self) -> i16 {
58        self.code
59    }
60}
61
62impl fmt::Display for AcceptError {
63    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
64        self.code.fmt(f)
65    }
66}