348 lines
9.5 KiB
Rust
348 lines
9.5 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 collection;
|
|
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)
|
|
}
|
|
|
|
/// **Internal**
|
|
///
|
|
/// add implementation of a collection
|
|
#[proc_macro_attribute]
|
|
pub fn collection(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::collection::collection(attrs, input)
|
|
}
|
|
|
|
/// **Internal**
|
|
///
|
|
/// add implementation of a `BokBuilderDeps` trait
|
|
#[::macro_magic::import_tokens_attr]
|
|
#[proc_macro_attribute]
|
|
pub fn collection_dep(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::collection::collection_dep(attrs, input, __source_path)
|
|
}
|
|
|
|
//
|
|
// ####### 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 {}
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::pkgs::package(attrs, input)
|
|
}
|
|
|
|
/// **Internal**. try not to use
|
|
/// Use as #[::bok::package(MyBasePackage<R>)]
|
|
/// Will setup a `base` field that is the given base package
|
|
/// and add `#[derive(::bok::Package)]`
|
|
/// needs generics
|
|
///
|
|
/// e.g.:
|
|
/// ```
|
|
/// #[::bok::package_path(::base::pkg<R>)]
|
|
/// pub struct MyPkg {}
|
|
/// ```
|
|
#[::macro_magic::import_tokens_attr]
|
|
#[proc_macro_attribute]
|
|
pub fn package_path(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::pkgs::package_path(attrs, input, __source_path)
|
|
}
|
|
|
|
/// Specify one or more dependencies
|
|
///
|
|
/// e.g:
|
|
/// ```
|
|
/// #[::bok::package(::bok::PkgEmpty)]
|
|
/// #[::bok::deps(some::Package, other::Package)]
|
|
/// pub struct MyPkg {}
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn deps(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::pkgs::deps(attrs, input)
|
|
}
|
|
|
|
/*
|
|
/// attribute for package optional feature fields
|
|
/// marks a struct field as a package option
|
|
/// the PkgBuilder will create apposite get/set and traits for the options
|
|
///
|
|
/// e.g:
|
|
/// ```
|
|
/// #[::bok::package(::bok::PkgEmpty)]
|
|
/// pub struct MyPkg {
|
|
/// #[::bok::option]
|
|
/// with_ssl: bool,
|
|
/// }
|
|
/// ```
|
|
#[proc_macro_attribute]
|
|
pub fn option(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
|
crate::pkgs::option(attrs, input)
|
|
}
|
|
*/
|
|
|
|
/// Use as #[::bok::package_impl]
|
|
/// adds the right generics to the package.
|
|
///
|
|
/// extra calls and changes are added to `::bok::Pkg` and ::std::Default traits
|
|
///
|
|
/// e.g.:
|
|
/// ```
|
|
/// #[::bok::package_impl]
|
|
/// impl Default for Mypackage {
|
|
/// fn default() -> Self { ... }
|
|
/// }
|
|
/// #[::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)
|
|
}
|
|
|
|
/// ** Internal, don't use unless you know what you are doing.**
|
|
/// Use as #[::bok::package_impl_builder(::my::Package)]
|
|
/// implements common ::bok::PkgBuilder 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_builder(MyPackage)]
|
|
/// #[::macro_magic::export_tokens(_bok_pkgbuilder_mypackage)]
|
|
/// impl ::bok::PkgBuilder for MyPackage {
|
|
/// fn set_dependencies(&self, ...) -> Result<(),()> {
|
|
/// ...
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
#[::macro_magic::import_tokens_attr]
|
|
#[proc_macro_attribute]
|
|
pub fn package_impl_builder(
|
|
attrs: TokenStream,
|
|
input: TokenStream,
|
|
) -> TokenStream {
|
|
crate::pkgs::package_impl_builder(attrs, input, __source_path)
|
|
}
|
|
|
|
/// 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, attributes(option))]
|
|
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))
|
|
}
|
|
}
|