///|
/// A logical scalar produced or consumed by an adapter.
pub(all) enum ScalarValue {
Text(String)
Numeric(@smithy.NodeNumber)
Flag(Bool)
} derive(Eq, Debug)
///|
fn ScalarValue::kind(self : ScalarValue) -> @contract.JsonKind {
match self {
Text(_) => StringKind
Numeric(_) => NumberKind
Flag(_) => BooleanKind
}
}
///|
/// An adapter refusal, at a path relative to the value that the adapter reads.
pub struct AdapterFailure {
path : @validation.InstancePath
message : String
} derive(Eq, Debug)
///|
pub fn AdapterFailure::new(
message : String,
path~ : @validation.InstancePath = @validation.InstancePath::root(),
) -> AdapterFailure {
{ path, message, }
}
///|
/// What an adapter may do during one call: charge work to the request.
pub struct AdapterContext {
priv meter : @validation.WorkMeter
}
///|
/// Charge `units` of work. False means that the request has no work left; the adapter must then fail.
pub fn AdapterContext::charge(self : AdapterContext, units : Int32) -> Bool {
self.meter.charge(units)
}
///|
/// A trusted host scalar adapter. It reads its declared JSON kinds into one logical scalar, writes the
/// canonical spelling of that scalar and may order dictionary keys. A model can name it, but only the host
/// can register it.
pub struct ScalarAdapter {
signature : @contract.AdapterSignature
priv reader : (Json, AdapterContext) -> Result[ScalarValue, AdapterFailure]
priv writer : (ScalarValue, AdapterContext) -> Result[Json, AdapterFailure]
priv compare : ((String, String) -> Int32)?
}
///|
pub fn ScalarAdapter::new(
id : @contract.AdapterId,
inputs~ : Array[@contract.JsonKind],
output~ : @contract.JsonKind,
read~ : (Json, AdapterContext) -> Result[ScalarValue, AdapterFailure],
write~ : (ScalarValue, AdapterContext) -> Result[Json, AdapterFailure],
compare~ : ((String, String) -> Int32)? = None,
) -> ScalarAdapter raise @contract.IdentityError {
let signature = @contract.AdapterSignature::new(
id,
inputs~,
output~,
orders_keys=compare is Some(_),
)
{ signature, reader: read, writer: write, compare, }
}
///|
pub fn ScalarAdapter::id(self : ScalarAdapter) -> @contract.AdapterId {
self.signature.id
}
///|
/// The adapters that a host trusts, by identifier.
pub struct AdapterRegistry {
priv adapters : Map[@contract.AdapterId, ScalarAdapter]
}
///|
pub fn AdapterRegistry::new() -> AdapterRegistry {
{ adapters: Map([]), }
}
///|
/// Register an adapter. Registering a second adapter with the same identifier is refused.
pub fn AdapterRegistry::register(
self : AdapterRegistry,
adapter : ScalarAdapter,
) -> AdapterRegistry raise @validation.ConfigurationError {
if self.adapters.contains(adapter.id()) {
raise @validation.ConfigurationError(
"I already have an adapter \{adapter.id()}.",
)
}
let adapters = Map::from_iter(self.adapters.iter())
adapters[adapter.id()] = adapter
{ adapters, }
}
///|
pub fn AdapterRegistry::signatures(
self : AdapterRegistry,
) -> Array[@contract.AdapterSignature] {
self.adapters.values().map(a => a.signature).to_array()
}
///|
pub fn AdapterRegistry::get(
self : AdapterRegistry,
id : @contract.AdapterId,
) -> ScalarAdapter? {
self.adapters.get(id)
}
///|
/// The exact number of a JSON number, using its retained token when present.
pub fn json_number(value : Json) -> @smithy.NodeNumber? {
match value {
Number(n, repr~) => @smithy.NodeNumber::parse(repr.unwrap_or(n.to_string()))
_ => None
}
}
///|
/// A JSON number that keeps the exact token of `n`.
pub fn number_json(n : @smithy.NodeNumber) -> Json {
Json::number(n.approximate, repr=n.to_string())
}