bok/bok-macro/src/lib.rs
Luca Fulchir 00e93ce612
Package dependencies
Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
2024-12-02 12:21:29 +01:00

270 lines
7.3 KiB
Rust

/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* Licensed under the Apache License, Version 2.0 with LLVM exception (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License and of the exception at
*
* http://www.apache.org/licenses/LICENSE-2.0
* https://spdx.org/licenses/LLVM-exception.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![feature(proc_macro_span)]
use ::proc_macro::TokenStream;
mod pkgs;
mod repos;
//
// ####### Repository stuff ##########
//
/// Use as #[::bok::repository(MyBaseRepo)]
/// Will setup a `base` field that is the given base repo
/// and add `#[derive(::bok::Repository)]`
///
/// e.g.: `#[::bok::repository(::bok::RepositoryEmpty)]`
#[::macro_magic::import_tokens_attr]
//#[with_custom_parsing(repos::BaseSet)]
#[proc_macro_attribute]
pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::repos::repository(attrs, input)
}
/// Unless you know what you are doing, use `#[::bok::repository(MyBaseRepo)]`
/// instead needs a `.base` field
///
/// Use like:
/// ```
/// #[derive(::bok::Repository)]
/// pub struct MyRepo {
/// base : BaseRepo,
/// }
/// ```
/// adds extension capabilities to a repo
#[proc_macro_derive(Repository)]
pub fn derive_repository(input: TokenStream) -> TokenStream {
crate::repos::derive_repository(input)
}
/// Add multiple packages to a repo
/// Usage:
/// ```
/// #[::bok::repo_packages(Mypkg1, Mypkg2)]
/// struct MyRepo{}
/// ```
#[proc_macro_attribute]
pub fn repo_packages(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::repos::repo_packages(attrs, input)
}
/// Create the methods that will return the builders and packages
///
/// will actually merely rewrite the macro to get the actual Repo name
/// in `#[::bok_macro::repo_impl_methods(MyRepo)]`
///
/// Usage:
/// ```
/// #[::bok::repo_impl]
/// impl MyRepo{}
/// ```
//#[::macro_magic::import_tokens_attr]
#[proc_macro_attribute]
pub fn repo_impl(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::repos::repo_impl(attrs, input)
}
/// Internal. **Do not use unless you know what you are doing**
/// Create the methods that will return the builders and packages
/// Usage:
/// ```
/// #[::bok_macro::repo_impl_methods(MyRepo)]
/// impl MyRepo{}
/// ```
#[::macro_magic::import_tokens_attr]
#[proc_macro_attribute]
pub fn repo_impl_methods(
attrs: TokenStream,
input: TokenStream,
) -> TokenStream {
crate::repos::repo_impl_methods(attrs, input, __source_path)
}
/// Internal. **Do not use unless you know what you are doing**
/// given a Repository and a trait "BokDeps...",
/// implement all the fn returning the dependencies needed by the package
///
/// Usage:
/// ```
/// #[::bok_macro::repo_impl_(MyRepo)]
/// impl MyRepo{}
/// ```
#[::macro_magic::import_tokens_attr]
#[proc_macro_attribute]
pub fn repo_impl_pkg_deps(
attrs: TokenStream,
input: TokenStream,
) -> TokenStream {
crate::repos::repo_impl_pkg_deps(attrs, input)
}
//
// ####### Package stuff ##########
//
/// Use on a function as `#[::bok::pkg_fn_to_code]`
/// will create a new function, same name with `_code` that
/// returns the ::proc_macro2::TokenStream of the function
///
/// **Don't use this if you are using `#[::bok::package(...)]`
/// it is already automatically added to all members of trait `::bok::Pkg`**
///
/// e.g.:
/// ```
/// impl MyPackage {
/// #[::bok::pkg_fn_to_code]
/// fn build() {
/// ...
/// }
/// }
/// let p = MyPackage::default();
/// let tokens : ::proc_macro2::TokenStream = p.build_code()
/// ```
#[proc_macro_attribute]
pub fn pkg_fn_to_code(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::pkgs::pkg_fn_to_code(attrs, input)
}
/// Use as #[::bok::package(MyBasePackage)]
/// Will setup a `base` field that is the given base package
/// and add `#[derive(::bok::Package)]`
///
/// e.g.:
/// ```
/// #[::bok::package(::bok::PkgEmpty)]
/// pub struct MyPkg {}
/// ```
#[::macro_magic::import_tokens_attr]
#[proc_macro_attribute]
pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::pkgs::package(attrs, input, __source_path)
}
/// Specify one or more build-time dependencies
///
/// e.g:
/// ```
/// #[::bok::package(::bok::PkgEmpty)]
/// #[::bok::deps_build(some::Package, other::Package)]
/// pub struct MyPkg {}
/// ```
#[proc_macro_attribute]
pub fn deps_build(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::pkgs::deps_build(attrs, input)
}
/// Use as #[::bok::package_impl]
/// will add `#[::bok::package_impl_base(..)]` with proper arguments
/// and export the resulting symbols
///
/// e.g.:
/// ```
/// #[::bok::package_impl]
/// impl ::bok::Pkg for MyPackage {
/// fn build(&self) -> Result<(),()> {
/// ...
/// }
/// }
/// ```
#[proc_macro_attribute]
pub fn package_impl(attrs: TokenStream, input: TokenStream) -> TokenStream {
crate::pkgs::package_impl(attrs, input)
}
/// Internal, **don't use unless you know what you are doing.**
/// Use as #[::bok::package_impl_base(::my::Package)]
/// implements common ::bok::Pkg methods and takes the package methods
/// not implemented by the user from the base package
///
/// does not export symbols.
///
/// should be called with the same path as the package that implements
/// ::bok::Pkg
///
/// will rewrite itself with the exported impl path of the base package
/// so that macro_magic can import the base impl
///
/// e.g.:
/// ```
/// #[::bok::package_impl_base(MyPackage)]
/// #[::macro_magic::export_tokens(bok_pkg_mypackage)]
/// impl ::bok::Pkg for MyPackage {
/// fn build(&self) -> Result<(),()> {
/// ...
/// }
/// }
/// ```
#[::macro_magic::import_tokens_attr]
#[proc_macro_attribute]
pub fn package_impl_base(
attrs: TokenStream,
input: TokenStream,
) -> TokenStream {
crate::pkgs::package_impl_base(attrs, input)
}
/// Unless you know what you are doing, use `#[::bok::package(MyBasePackage)]`
/// instead needs a `.base` field
///
/// ```
/// #[derive(::bok::Package)]
/// pub struct MyPkg {
/// base: OtherPkg
/// }
/// ```
/// adds:
/// * Builder pattern to a package
/// * getters/setters for all package fields
/// * deref for package
#[proc_macro_derive(Package)]
pub fn derive_package(input: TokenStream) -> TokenStream {
crate::pkgs::derive_package(input)
}
// ==== Common package stuff ====
pub(crate) struct PathList(Vec<::syn::Path>);
impl ::syn::parse::Parse for PathList {
fn parse(input: ::syn::parse::ParseStream) -> syn::Result<Self> {
use ::syn::punctuated::Punctuated;
let raw =
Punctuated::<::syn::Path, ::syn::Token![,]>::parse_terminated(
input,
)?;
let mut result = Vec::with_capacity(raw.len());
for r in raw.into_iter() {
result.push(r)
}
Ok(PathList(result))
}
}
pub(crate) fn path_to_magic_export(p: &::syn::Path) -> ::syn::Path {
let mut tmp = p.clone();
let new_id = {
macro_magic::mm_core::export_tokens_macro_ident(
&tmp.segments.last().unwrap().ident,
)
};
tmp.segments.last_mut().unwrap().ident = new_id;
tmp
}