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
// Copyright (c) 2020 Timo Savola.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

//! Service binding implementation support.

use crate::core;
use crate::packet::Code;
use crate::stream::{RecvStream, RecvWriteStream, WriteStream};

pub mod future {
    pub use crate::core::CallFuture as Call;
    pub use crate::core::InfoRecvFuture as InfoRecv;
    pub use crate::core::InfoSendFuture as InfoSend;
}

/// Reason for service registration failure.
#[derive(Debug)]
pub enum RegistrationError {
    NameAlreadyRegistered,
    TooManyServices,
}

/// Handle to a registered service.
///
/// If a stream is opened as a result of service registration or a call, the
/// appropriate stream constructor must be called immediately.  Care must be
/// taken when using input buffering with streams which carry stream ids.
pub struct Service {
    code: Code,
}

impl Service {
    /// Register a service or panic.
    pub fn register(name: &'static str) -> Self {
        match Self::try_register(name) {
            Ok(this) => this,
            Err(e) => panic!("{}: {:?}", name, e),
        }
    }

    /// Register a service.
    pub fn try_register(name: &'static str) -> Result<Self, RegistrationError> {
        Ok(Self {
            code: core::register_service(name)?,
        })
    }

    /// Call the service.  Returns a future.
    ///
    /// The receptor is invoked with the reply content, and its return value is
    /// passed through.
    pub fn call<'a, R, T>(&self, content: &'a [u8], receptor: R) -> future::Call<'a, R, T>
    where
        R: FnOnce(&[u8]) -> T + Unpin,
    {
        future::Call::new(self.code, content, receptor)
    }

    /// Receive info packets from the service repeatedly.  Returns a future.
    pub fn recv_info<R>(&self, receptor: R) -> future::InfoRecv<R>
    where
        R: Fn(&[u8]) + Unpin,
    {
        future::InfoRecv::new(self.code, receptor)
    }

    /// Send an info packet to the service.  Returns a future.
    pub fn send_info<'a>(&self, content: &'a [u8]) -> future::InfoSend<'a> {
        future::InfoSend::new(self.code, content)
    }

    /// Construct a handle to a new bidirectional stream.
    pub fn stream(&self, id: i32) -> RecvWriteStream {
        RecvWriteStream::new(core::init_stream(
            self.code,
            id,
            core::STREAM_SELF_FLOW
                | core::STREAM_SELF_DATA
                | core::STREAM_PEER_FLOW
                | core::STREAM_PEER_DATA,
        ))
    }

    /// Construct a handle to a new unidirectional stream.
    pub fn input_stream(&self, id: i32) -> RecvStream {
        RecvStream::new(core::init_stream(
            self.code,
            id,
            core::STREAM_SELF_FLOW | core::STREAM_PEER_DATA,
        ))
    }

    /// Construct a handle to a new unidirectional stream.
    pub fn output_stream(&self, id: i32) -> WriteStream {
        WriteStream::new(core::init_stream(
            self.code,
            id,
            core::STREAM_SELF_DATA | core::STREAM_PEER_FLOW,
        ))
    }
}