use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use super::call::{Action, Call};
use super::call_result::CallResultRaw;
use super::parse::{self, Message, TypedMessage};
use super::typed_call_result::TypedCallResult;
use crate::errors::{Error, Result};
#[derive(Debug, Default, Clone)]
pub struct PendingCalls {
pending: BTreeMap<String, Action>,
}
impl PendingCalls {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, unique_id: impl Into<String>, action: Action) {
self.pending.insert(unique_id.into(), action);
}
pub fn register_call(&mut self, call: &Call) {
self.register(call.unique_id.clone(), call.payload.clone());
}
pub fn take(&mut self, unique_id: &str) -> Option<Action> {
self.pending.remove(unique_id)
}
#[must_use]
pub fn len(&self) -> usize {
self.pending.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.pending.is_empty()
}
pub fn resolve(&mut self, raw: CallResultRaw) -> Result<TypedCallResult> {
let action = self
.pending
.remove(&raw.unique_id)
.ok_or_else(|| Error::UnknownPendingMessageId(raw.unique_id.clone()))?;
TypedCallResult::resolve(raw, &action)
}
pub fn send_call(&mut self, call: Call) -> Result<String> {
self.register_call(&call);
parse::serialize_message(&Message::Call(call))
}
pub fn deserialize_typed(&mut self, data: &str) -> Result<TypedMessage> {
let message = parse::deserialize_to_message(data)?;
self.message_to_typed(message)
}
pub fn message_to_typed(&mut self, message: Message) -> Result<TypedMessage> {
match message {
Message::Call(call) => Ok(TypedMessage::Call(call)),
Message::CallResult(raw) => {
let typed = self.resolve(raw)?;
Ok(TypedMessage::CallResult(typed))
}
Message::CallError(e) => Ok(TypedMessage::CallError(e)),
Message::CallResultError(e) => Ok(TypedMessage::CallResultError(e)),
Message::Send(s) => Ok(TypedMessage::Send(s)),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct PendingActionNames {
pending: BTreeMap<String, String>,
}
impl PendingActionNames {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, unique_id: impl Into<String>, action_name: impl Into<String>) {
self.pending.insert(unique_id.into(), action_name.into());
}
pub fn register_call(&mut self, call: &Call) {
self.register(call.unique_id.clone(), call.payload.action_name());
}
pub fn take(&mut self, unique_id: &str) -> Option<String> {
self.pending.remove(unique_id)
}
#[must_use]
pub fn len(&self) -> usize {
self.pending.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.pending.is_empty()
}
pub fn resolve(&mut self, raw: CallResultRaw) -> Result<TypedCallResult> {
let action_name = self
.pending
.remove(&raw.unique_id)
.ok_or_else(|| Error::UnknownPendingMessageId(raw.unique_id.clone()))?;
TypedCallResult::resolve_from_action_name(raw, &action_name)
}
pub fn send_call(&mut self, call: Call) -> Result<String> {
self.register_call(&call);
parse::serialize_message(&Message::Call(call))
}
pub fn deserialize_typed(&mut self, data: &str) -> Result<TypedMessage> {
let message = parse::deserialize_to_message(data)?;
match message {
Message::Call(call) => Ok(TypedMessage::Call(call)),
Message::CallResult(raw) => Ok(TypedMessage::CallResult(self.resolve(raw)?)),
Message::CallError(e) => Ok(TypedMessage::CallError(e)),
Message::CallResultError(e) => Ok(TypedMessage::CallResultError(e)),
Message::Send(s) => Ok(TypedMessage::Send(s)),
}
}
}
pub fn resolve_with_action_name(raw: CallResultRaw, action_name: &str) -> Result<TypedCallResult> {
TypedCallResult::resolve_from_action_name(raw, action_name)
}
pub fn try_resolve_unique(raw: &CallResultRaw) -> Result<TypedCallResult> {
let mut candidates = raw.probe_candidates();
match candidates.len() {
1 => {
Ok(candidates.remove(0))
}
0 => Err(Error::AmbiguousCallResult(
"payload matched no known OCPP 2.1 response schema".to_string(),
)),
n => {
let names: Vec<&str> = candidates
.iter()
.map(TypedCallResult::action_name)
.collect();
Err(Error::AmbiguousCallResult(format!(
"payload matched {n} response schemas: {names:?}"
)))
}
}
}