Skip to content

Instantly share code, notes, and snippets.

@malcolmgreaves
Created January 5, 2026 23:28
Show Gist options
  • Select an option

  • Save malcolmgreaves/7439701bd7b88b59115b54392675adbc to your computer and use it in GitHub Desktop.

Select an option

Save malcolmgreaves/7439701bd7b88b59115b54392675adbc to your computer and use it in GitHub Desktop.
A macro for a newtype with custom construction validation logic.
#[derive(Debug)]
pub enum Error {
InvalidMarkdown,
InvalidLlmTxtFormat,
Unknown(String),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<error>")
}
}
impl std::error::Error for Error {}
/// Construct a new zero-zied type wrapper around a to-be-validated value.
/// The newtype only exists for values that are valid according to the $is_valid function.
macro_rules! newtype_valid {
($name:ident, $inner:path, $is_valid:expr, $error:path, $new_error:expr) => {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct $name($inner);
impl std::fmt::Display for $name {
/// Displays $inner only.
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl $name {
/// Create a new instance of $name if the $inner value is valid. Returns an error on failure.
pub fn new(maybe_valid_inner: $inner) -> Result<Self, $error> {
if Self::is_valid(&maybe_valid_inner) {
Ok($name(maybe_valid_inner))
} else {
let e: $error = $new_error(&maybe_valid_inner);
Err(e)
}
}
/// True if the $inner value is a valid instance of $name. False otherwise.
pub fn is_valid(maybe_valid_inner: &$inner) -> bool {
$is_valid(maybe_valid_inner)
}
/// Apply a function to transform the $inner value into a new instance.
/// If the new instance isn't valid, then this results in an instance of `Err($error)`.
/// Otherwise, it's an `Ok` of the new $inner value wrapped as a $name.
pub fn map<F>(&self, f: F) -> Result<$name, $error>
where
F: FnOnce(&$inner) -> Result<$inner, $error>,
{
f(&self.0).map($name)
}
/// Destroys the $name wrapper, obtaining the $inner value directly.
pub fn extract(self) -> $inner {
self.0
}
}
};
}
fn is_valid_markdown(s: &str) -> bool { unimplemented!() }
newtype_valid!(Markdown, String, is_valid_markdown, Error, |_| {
Error::InvalidMarkdown
});
fn is_valid_llm_txt(md: &Markdown) -> bool { unimplemented!() }
newtype_valid!(LlmTxt, Markdown, is_valid_llm_txt, Error, |_| {
Error::InvalidLlmTxtFormat
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment