Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["eager2", "eager2-core"]
members = ["eager2", "eager2-core", "dummy"]

[workspace.dependencies]
eager2-core = { path = "./eager2-core", version = "1.1.2" }
20 changes: 20 additions & 0 deletions dummy/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "dummy"
version = "1.1.2"
authors = ["Daniel Bloom"]
edition = "2021"
categories = ["development-tools"]
description = "Proc-macros for eager macro expansion"
documentation = "https://docs.rs/eager2"
license = "MIT"
repository = "https://github.com/Daniel-Aaron-Bloom/eager2"
readme = "../README.md"
rust-version = "1.88"

[lib]
proc-macro = true
path = "src/lib.rs"

[dependencies]
eager2 = { path = "../eager2" }
eager2-core = { workspace = true }
10 changes: 10 additions & 0 deletions dummy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use eager2::eager_proc_macro;
use proc_macro::{Punct, Spacing, TokenStream, TokenTree};

#[eager_proc_macro]
pub fn add(input: TokenStream) -> TokenStream {
let mut res = TokenStream::new();
res.extend([TokenTree::from(Punct::new('+', Spacing::Alone))]);
res.extend(input.into_iter().collect::<Vec<TokenTree>>());
res
}
2 changes: 1 addition & 1 deletion eager2-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ proc-macro2 = { version = "1", optional = true }
quote = { version = "1", optional = true }

[features]
"testing" = ["proc-macro2", "quote"]
testing = ["dep:proc-macro2", "dep:quote"]
201 changes: 201 additions & 0 deletions eager2-core/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
use std::{
borrow::Cow,
collections::VecDeque,
env,
error::Error as StdError,
fmt::{self, Debug, Formatter, Write},
ops::{Deref, DerefMut},
process::{Command, ExitCode, Termination},
rc::Rc,
};

#[repr(transparent)]
struct Error(Rc<dyn StdError>);

impl<T: StdError + 'static> From<T> for Error {
fn from(value: T) -> Self {
Self(Rc::new(value))
}
}

impl Deref for Error {
type Target = Rc<dyn StdError>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Error {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_char('\n')?;
let mut errors = VecDeque::from([&*self.0]);
while let Some(src) = self.0.source() {
errors.push_front(src);
}
for (i, err) in errors.iter().enumerate() {
writeln!(f, "\t#{i}: {err}")?;
}
Ok(())
}
}

#[derive(Debug)]
struct ErrString(Cow<'static, str>);

impl StdError for ErrString {}

impl fmt::Display for ErrString {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.0.to_string().as_str())
}
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum RustcChannel {
Stable,
Beta,
Nightly,
}

impl fmt::Display for RustcChannel {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::Stable => "stable",
Self::Beta => "beta",
Self::Nightly => "nightly",
})
}
}

#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct RustcVersion {
major: u32,
minor: u32,
patch: u32,
channel: RustcChannel,
}

impl TryFrom<(&str, &str, &str, &str)> for RustcVersion {
type Error = Error;
fn try_from(value: (&str, &str, &str, &str)) -> Result<Self, Self::Error> {
Ok(Self {
major: value.0.parse()?,
minor: value.1.parse()?,
patch: value.2.parse()?,
channel: match value.3.to_lowercase().as_str() {
"stable" => Ok(RustcChannel::Stable),
"beta" => Ok(RustcChannel::Beta),
"nightly" => Ok(RustcChannel::Nightly),
s => Err(ErrString(format!("unknown rust channel: {s}").into())),
}?,
})
}
}

impl fmt::Display for RustcVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"rustc {}.{}.{}-{}",
self.major, self.minor, self.patch, self.channel
)
}
}

fn main() -> Result<impl Termination, Error> {
let rustc = env::var("RUSTC")?;
let output = Command::new(rustc).arg("--version").output()?;
if !output.status.success() {
return Ok(ExitCode::from(
output
.status
.code()
.expect("could not retrieve status code") as u8,
));
}
let stdout = output
.stdout
.trim_ascii_start()
.strip_prefix(b"rustc ")
.expect("rustc version output does not start with \"rustc\"");

let next_sep = stdout
.iter()
.position(|byte| *byte == b'.')
.expect("could not retrieve rustc major version");
let maj = &stdout[0..next_sep];
let stdout = unsafe {
stdout
.strip_prefix(maj)
.unwrap_unchecked()
.strip_prefix(b".")
.unwrap_unchecked()
};

let next_sep = stdout
.iter()
.position(|byte| *byte == b'.')
.expect("could not retrieve rustc minor version");
let min = &stdout[0..next_sep];
let stdout = unsafe {
stdout
.strip_prefix(min)
.unwrap_unchecked()
.strip_prefix(b".")
.unwrap_unchecked()
};

let mut have_channel_info = false;
let next_sep = stdout
.iter()
.position(|byte| {
if *byte == b'-' {
have_channel_info = true;
}
byte.is_ascii_whitespace() || *byte == b'-'
})
.expect("could not retrieve rustc major version");
let patch = &stdout[0..next_sep];
let stdout = unsafe {
stdout
.strip_prefix(patch)
.unwrap_unchecked()
.strip_prefix(if have_channel_info {
b"-".as_slice()
} else {
b""
})
.unwrap_unchecked()
.trim_ascii_start()
};

let channel = if have_channel_info {
stdout
.iter()
.take_while(|byte| !byte.is_ascii_whitespace())
.copied()
.collect()
} else {
b"stable".to_vec()
};

let rustversion: RustcVersion = (
str::from_utf8(maj)?,
str::from_utf8(min)?,
str::from_utf8(patch)?,
str::from_utf8(&channel)?,
)
.try_into()?;

println!("cargo::rustc-check-cfg=cfg(rustchan, values(\"stable\", \"beta\", \"nightly\"))");
println!("cargo::rustc-cfg=rustchan=\"{}\"", rustversion.channel);

Ok(ExitCode::SUCCESS)
}
21 changes: 21 additions & 0 deletions eager2-core/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,36 @@ pub const LAZY_SIGIL: &str = "𓆉";
pub const EAGER_SIGIL: &str = "𓂺";

#[must_use]
#[inline(always)]
pub fn get_eager_2_ident() -> Ident {
Ident::new(EAGER2_IDENT, Span::call_site())
}

#[must_use]
#[inline(always)]
pub(crate) fn get_eager_2_pm_ident(suffix: Option<&str>) -> Ident {
Ident::new(
format!("{EAGER2_IDENT}{s}", s = suffix.unwrap_or_default()).as_str(),
Span::call_site(),
)
}

#[must_use]
#[inline(always)]
pub fn eager_call_sigil() -> Literal {
Literal::from_str(EAGER_CALL_SIGIL).unwrap()
}

#[must_use]
#[inline(always)]
pub(crate) fn eager_call_sigil_proc_macro() -> TokenStream {
use crate::interpolate;

interpolate! {
::proc_macro::Literal::from_str(#EAGER_CALL_SIGIL).unwrap()
}
}

#[must_use]
pub fn crate_path() -> TokenStream {
let mut tokens = TokenStream::new();
Expand Down
26 changes: 25 additions & 1 deletion eager2-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! This library is not meant for public consumption
#![cfg_attr(rustchan = "nightly", feature(proc_macro_span))]
#![recursion_limit = "1024"]

//! This library is not meant for public consumption
#![doc(hidden)]

use std::borrow::Cow;
Expand Down Expand Up @@ -52,6 +54,28 @@ pub mod pm {
tokens.extend([self.clone()]);
}
}
impl ToTokens for TokenStream {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend([self.clone()]);
}
}
impl ToTokens for &str {
fn to_tokens(&self, tokens: &mut TokenStream) {
Literal::string(self).to_tokens(tokens);
}
}
impl<const N: usize, T: ToTokens> ToTokens for [T; N] {
fn to_tokens(&self, tokens: &mut TokenStream) {
for item in self {
item.to_tokens(tokens);
}
}
}
impl<T: ToTokens> ToTokens for &T {
fn to_tokens(&self, tokens: &mut TokenStream) {
(*self).to_tokens(tokens);
}
}
}

#[cfg(feature = "testing")]
Expand Down
Loading
Loading