#[macro_export]
macro_rules! elicit_newtype {
($inner_path:path, as $wrapper_name:ident) => {
#[doc = concat!("Elicitation-enabled wrapper around `", stringify!($inner_path), "`.")]
#[doc = ""]
#[doc = "This newtype uses `Arc` internally to ensure `Clone` is always available,"]
#[doc = "providing transparent access via `Deref` and `DerefMut`."]
#[derive(
::std::fmt::Debug,
::std::clone::Clone,
)]
pub struct $wrapper_name(pub ::std::sync::Arc<$inner_path>);
impl ::schemars::JsonSchema for $wrapper_name {
fn schema_name() -> ::std::borrow::Cow<'static, str> {
stringify!($wrapper_name).into()
}
fn json_schema(_gen: &mut ::schemars::SchemaGenerator) -> ::schemars::Schema {
::schemars::json_schema!({
"type": "object",
"description": concat!(
"Elicitation-enabled wrapper around `",
stringify!($inner_path),
"`"
)
})
}
}
impl ::std::ops::Deref for $wrapper_name {
type Target = $inner_path;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl ::std::ops::DerefMut for $wrapper_name {
fn deref_mut(&mut self) -> &mut Self::Target {
::std::sync::Arc::get_mut(&mut self.0)
.expect("Cannot get mutable reference to Arc with multiple references")
}
}
impl ::std::convert::AsRef<$inner_path> for $wrapper_name {
fn as_ref(&self) -> &$inner_path {
&*self.0
}
}
impl ::std::convert::From<$inner_path> for $wrapper_name {
fn from(inner: $inner_path) -> Self {
Self(::std::sync::Arc::new(inner))
}
}
impl ::std::convert::From<::std::sync::Arc<$inner_path>> for $wrapper_name {
fn from(arc: ::std::sync::Arc<$inner_path>) -> Self {
Self(arc)
}
}
impl ::std::convert::From<$wrapper_name> for ::std::sync::Arc<$inner_path> {
fn from(wrapper: $wrapper_name) -> Self {
wrapper.0
}
}
impl $crate::Prompt for $wrapper_name {
fn prompt() -> ::std::option::Option<&'static str> {
None
}
}
impl $crate::Elicitation for $wrapper_name {
type Style = ();
async fn elicit<C: $crate::ElicitCommunicator>(
_communicator: &C,
) -> $crate::ElicitResult<Self> {
Err($crate::ElicitError::new($crate::ElicitErrorKind::ParseError(
concat!(
"elicit() for `",
stringify!($wrapper_name),
"` requires the serde variant. Use `elicit_newtype!(",
stringify!($inner_path),
", as ",
stringify!($wrapper_name),
", serde)` or implement `Elicitation` manually."
)
.to_string(),
)))
}
fn kani_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::kani_trusted_opaque(stringify!($wrapper_name))
}
fn verus_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::verus_trusted_opaque(stringify!($wrapper_name))
}
fn creusot_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::creusot_trusted_opaque(stringify!($wrapper_name))
}
}
impl $crate::ElicitIntrospect for $wrapper_name {
fn pattern() -> $crate::ElicitationPattern {
$crate::ElicitationPattern::Primitive
}
fn metadata() -> $crate::TypeMetadata {
$crate::TypeMetadata {
type_name: stringify!($wrapper_name),
description: None,
details: $crate::PatternDetails::Primitive,
}
}
}
#[cfg(feature = "prompt-tree")]
impl $crate::ElicitPromptTree for $wrapper_name {
fn prompt_tree() -> $crate::PromptTree {
$crate::PromptTree::Leaf {
prompt: stringify!($wrapper_name).to_string(),
type_name: stringify!($wrapper_name).to_string(),
}
}
}
impl $crate::ElicitSpec for $wrapper_name {
fn type_spec() -> $crate::TypeSpec {
$crate::TypeSpecBuilder::default()
.type_name(stringify!($wrapper_name).to_string())
.summary(
concat!(
"Elicitation-enabled newtype wrapper around `",
stringify!($inner_path),
"`."
)
.to_string(),
)
.build()
.expect("valid TypeSpec")
}
}
};
($inner_path:path, as $wrapper_name:ident, serde) => {
#[doc = concat!("Elicitation-enabled wrapper around `", stringify!($inner_path), "`.")]
#[doc = ""]
#[doc = "This newtype uses `Arc` internally to ensure `Clone` is always available,"]
#[doc = "providing transparent access via `Deref` and `DerefMut`."]
#[doc = "Serialization is delegated transparently to the inner type."]
#[derive(
::std::fmt::Debug,
::std::clone::Clone,
::serde::Serialize,
::serde::Deserialize,
)]
#[serde(transparent)]
pub struct $wrapper_name(pub ::std::sync::Arc<$inner_path>);
impl ::schemars::JsonSchema for $wrapper_name {
fn schema_name() -> ::std::borrow::Cow<'static, str> {
stringify!($wrapper_name).into()
}
fn json_schema(schema_gen: &mut ::schemars::SchemaGenerator) -> ::schemars::Schema {
<$inner_path as ::schemars::JsonSchema>::json_schema(schema_gen)
}
}
impl ::std::ops::Deref for $wrapper_name {
type Target = $inner_path;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl ::std::ops::DerefMut for $wrapper_name {
fn deref_mut(&mut self) -> &mut Self::Target {
::std::sync::Arc::get_mut(&mut self.0)
.expect("Cannot get mutable reference to Arc with multiple references")
}
}
impl ::std::convert::AsRef<$inner_path> for $wrapper_name {
fn as_ref(&self) -> &$inner_path {
&*self.0
}
}
impl ::std::convert::From<$inner_path> for $wrapper_name {
fn from(inner: $inner_path) -> Self {
Self(::std::sync::Arc::new(inner))
}
}
impl ::std::convert::From<::std::sync::Arc<$inner_path>> for $wrapper_name {
fn from(arc: ::std::sync::Arc<$inner_path>) -> Self {
Self(arc)
}
}
impl ::std::convert::From<$wrapper_name> for ::std::sync::Arc<$inner_path> {
fn from(wrapper: $wrapper_name) -> Self {
wrapper.0
}
}
impl $crate::Prompt for $wrapper_name {
fn prompt() -> ::std::option::Option<&'static str> {
None
}
}
impl $crate::Elicitation for $wrapper_name {
type Style = ();
async fn elicit<C: $crate::ElicitCommunicator>(
communicator: &C,
) -> $crate::ElicitResult<Self> {
let response = communicator
.send_prompt(concat!("Enter value for ", stringify!($wrapper_name)))
.await?;
let inner: $inner_path = $crate::serde_json::from_str(&response).or_else(|_| {
$crate::serde_json::from_str::<$inner_path>(&format!("\"{}\"", response))
})
.map_err(|e| {
$crate::ElicitError::new($crate::ElicitErrorKind::ParseError(
format!("Invalid {}: {}", stringify!($wrapper_name), e),
))
})?;
Ok(Self(::std::sync::Arc::new(inner)))
}
fn kani_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::kani_trusted_opaque(stringify!($wrapper_name))
}
fn verus_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::verus_trusted_opaque(stringify!($wrapper_name))
}
fn creusot_proof() -> $crate::proc_macro2::TokenStream {
$crate::verification::proof_helpers::creusot_trusted_opaque(stringify!($wrapper_name))
}
}
impl $crate::ElicitIntrospect for $wrapper_name {
fn pattern() -> $crate::ElicitationPattern {
$crate::ElicitationPattern::Primitive
}
fn metadata() -> $crate::TypeMetadata {
$crate::TypeMetadata {
type_name: stringify!($wrapper_name),
description: None,
details: $crate::PatternDetails::Primitive,
}
}
}
#[cfg(feature = "prompt-tree")]
impl $crate::ElicitPromptTree for $wrapper_name {
fn prompt_tree() -> $crate::PromptTree {
$crate::PromptTree::Leaf {
prompt: stringify!($wrapper_name).to_string(),
type_name: stringify!($wrapper_name).to_string(),
}
}
}
impl $crate::ElicitSpec for $wrapper_name {
fn type_spec() -> $crate::TypeSpec {
$crate::TypeSpecBuilder::default()
.type_name(stringify!($wrapper_name).to_string())
.summary(
concat!(
"Elicitation-enabled newtype wrapper around `",
stringify!($inner_path),
"`."
)
.to_string(),
)
.build()
.expect("valid TypeSpec")
}
}
};
}
#[macro_export]
macro_rules! elicit_newtype_traits {
($name:ident, $inner:path, []) => {};
($name:ident, $inner:path, [$flag:ident $(, $rest:ident)*]) => {
$crate::elicit_newtype_trait_flag!($name, $inner, $flag);
$crate::elicit_newtype_traits!($name, $inner, [$($rest),*]);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! elicit_newtype_trait_flag {
($name:ident, $inner:path, eq) => {
impl ::std::cmp::PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
*self.0 == *other.0
}
}
impl ::std::cmp::Eq for $name {}
};
($name:ident, $inner:path, eq_hash) => {
$crate::elicit_newtype_trait_flag!($name, $inner, eq);
impl ::std::hash::Hash for $name {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
(*self.0).hash(state);
}
}
};
($name:ident, $inner:path, ord) => {
$crate::elicit_newtype_trait_flag!($name, $inner, eq);
impl ::std::cmp::PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
(*self.0).partial_cmp(&*other.0)
}
}
impl ::std::cmp::Ord for $name {
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
(*self.0).cmp(&*other.0)
}
}
};
($name:ident, $inner:path, cmp) => {
$crate::elicit_newtype_trait_flag!($name, $inner, ord);
impl ::std::hash::Hash for $name {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
(*self.0).hash(state);
}
}
};
($name:ident, $inner:path, display) => {
impl ::std::fmt::Display for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::std::fmt::Display::fmt(&*self.0, f)
}
}
};
($name:ident, $inner:path, from_str) => {
impl ::std::str::FromStr for $name {
type Err = <$inner as ::std::str::FromStr>::Err;
fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
s.parse::<$inner>().map(Self::from)
}
}
};
}
#[macro_export]
macro_rules! elicit_newtypes {
() => {};
($inner_path:path, as $wrapper_name:ident $(;)?) => {
$crate::elicit_newtype!($inner_path, as $wrapper_name);
};
($inner_path:path, as $wrapper_name:ident; $($rest:tt)*) => {
$crate::elicit_newtype!($inner_path, as $wrapper_name);
$crate::elicit_newtypes!($($rest)*);
};
($inner_path:path, as $wrapper_name:ident, serde $(;)?) => {
$crate::elicit_newtype!($inner_path, as $wrapper_name, serde);
};
($inner_path:path, as $wrapper_name:ident, serde; $($rest:tt)*) => {
$crate::elicit_newtype!($inner_path, as $wrapper_name, serde);
$crate::elicit_newtypes!($($rest)*);
};
}