299 lines
8.5 KiB
Rust
299 lines
8.5 KiB
Rust
#![no_std]
|
|
|
|
//! [`git_ref_format`]: https://crates.io/crates/git-ref-format
|
|
//! [`radicle-git-ext`]: https://crates.io/crates/radicle-git-ext
|
|
//!
|
|
//! This crate depends on and re-exports from [`git_ref_format_core`].
|
|
//!
|
|
//! ## Macros
|
|
//!
|
|
//! Instead of providing procedural macros, like [`git_ref_format`]
|
|
//! it just provides much simpler declarative macros, guarded by the feature
|
|
//! flag `macro`.
|
|
//!
|
|
//! ### Benefits
|
|
//!
|
|
//! - Does not depend on [`radicle-git-ext`].
|
|
//! - Does not pull in procedural macro dependencies.
|
|
//! - Has much smaller compile-time overhead than [`git_ref_format`].
|
|
//!
|
|
//! ### Drawback
|
|
//!
|
|
//! The main drawback is that the macros in this crate cannot provide compile
|
|
//! time validation of the argument. Thus, these macros must be used in
|
|
//! conjunction with testing: If all generated objects are used in tests, and
|
|
//! these tests are run, then the guarantees are equally strong. Consumers that
|
|
//! do not or cannot test their code should not use the macros then.
|
|
|
|
pub use git_ref_format_core::*;
|
|
|
|
/// Create a [`git_ref_format_core::RefString`] from a string literal.
|
|
///
|
|
/// Similar to [`core::debug_assert`], an optimized build will not validate
|
|
/// (but rather perform an unsafe conversion) unless `-C debug-assertions` is
|
|
/// passed to the compiler.
|
|
#[cfg(any(feature = "macro", test))]
|
|
#[macro_export]
|
|
macro_rules! refname {
|
|
($arg:literal) => {{
|
|
use $crate::RefString;
|
|
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
RefString::try_from($arg).expect(core::concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be a valid reference name"
|
|
))
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
extern crate alloc;
|
|
|
|
use alloc::string::String;
|
|
|
|
let s: String = $arg.to_owned();
|
|
unsafe { core::mem::transmute::<_, RefString>(s) }
|
|
}
|
|
}};
|
|
}
|
|
|
|
/// Create a [`git_ref_format_core::Qualified`] from a string literal.
|
|
///
|
|
/// Similar to [`core::debug_assert`], an optimized build will not validate
|
|
/// (but rather perform an unsafe conversion) unless `-C debug-assertions` is
|
|
/// passed to the compiler.
|
|
#[cfg(any(feature = "macro", test))]
|
|
#[macro_export]
|
|
macro_rules! qualified {
|
|
($arg:literal) => {{
|
|
use $crate::Qualified;
|
|
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
Qualified::from_refstr($crate::refname!($arg)).expect(core::concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be of the form 'refs/<category>/<name>'"
|
|
))
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
extern crate alloc;
|
|
|
|
use core::mem::transmute;
|
|
|
|
use alloc::borrow::Cow;
|
|
use alloc::string::String;
|
|
|
|
use $crate::{RefStr, RefString};
|
|
|
|
let s: String = $arg.to_owned();
|
|
let refstring: RefString = unsafe { transmute(s) };
|
|
let cow: Cow<'_, RefStr> = Cow::Owned(refstring);
|
|
let qualified: Qualified = unsafe { transmute(cow) };
|
|
|
|
qualified
|
|
}
|
|
}};
|
|
}
|
|
|
|
/// Create a [`git_ref_format_core::Component`] from a string literal.
|
|
///
|
|
/// Similar to [`core::debug_assert`], an optimized build will not validate
|
|
/// (but rather perform an unsafe conversion) unless `-C debug-assertions` is
|
|
/// passed to the compiler.
|
|
#[cfg(any(feature = "macro", test))]
|
|
#[macro_export]
|
|
macro_rules! component {
|
|
($arg:literal) => {{
|
|
use $crate::Component;
|
|
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
Component::from_refstr($crate::refname!($arg)).expect(core::concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be a valid component (cannot contain '/')"
|
|
))
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
extern crate alloc;
|
|
|
|
use core::mem::transmute;
|
|
|
|
use alloc::borrow::Cow;
|
|
use alloc::string::String;
|
|
|
|
use $crate::{RefStr, RefString};
|
|
|
|
let s: String = $arg.to_owned();
|
|
let refstring: RefString = unsafe { transmute(s) };
|
|
let cow: Cow<'_, RefStr> = Cow::Owned(refstring);
|
|
let component: Component = unsafe { transmute(cow) };
|
|
|
|
component
|
|
}
|
|
}};
|
|
}
|
|
|
|
/// Create a [`git_ref_format_core::refspec::PatternString`] from a string literal.
|
|
///
|
|
/// Similar to [`core::debug_assert`], an optimized build will not validate
|
|
/// (but rather perform an unsafe conversion) unless `-C debug-assertions` is
|
|
/// passed to the compiler.
|
|
#[cfg(any(feature = "macro", test))]
|
|
#[macro_export]
|
|
macro_rules! pattern {
|
|
($arg:literal) => {{
|
|
use $crate::refspec::PatternString;
|
|
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
PatternString::try_from($arg).expect(core::concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be a valid refspec pattern"
|
|
))
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
extern crate alloc;
|
|
|
|
use alloc::string::String;
|
|
|
|
let s: String = $arg.to_owned();
|
|
unsafe { core::mem::transmute::<_, PatternString>(s) }
|
|
}
|
|
}};
|
|
}
|
|
|
|
/// Create a [`git_ref_format_core::refspec::QualifiedPattern`] from a string literal.
|
|
///
|
|
/// Similar to [`core::debug_assert`], an optimized build will not validate
|
|
/// (but rather perform an unsafe conversion) unless `-C debug-assertions` is
|
|
/// passed to the compiler.
|
|
#[cfg(any(feature = "macro", test))]
|
|
#[macro_export]
|
|
macro_rules! qualified_pattern {
|
|
($arg:literal) => {{
|
|
use $crate::refspec::QualifiedPattern;
|
|
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
use core::concat;
|
|
|
|
use $crate::refspec::PatternStr;
|
|
|
|
let pattern = PatternStr::try_from_str($arg).expect(concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be a valid refspec pattern"
|
|
));
|
|
|
|
QualifiedPattern::from_patternstr(pattern).expect(concat!(
|
|
"literal `",
|
|
$arg,
|
|
"` must be a valid qualified refspec pattern"
|
|
))
|
|
}
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
extern crate alloc;
|
|
|
|
use core::mem::transmute;
|
|
|
|
use alloc::borrow::Cow;
|
|
use alloc::string::String;
|
|
|
|
use $crate::refspec::{PatternStr, PatternString};
|
|
|
|
let s: String = $arg.to_owned();
|
|
let pattern: PatternString = unsafe { transmute(s) };
|
|
let cow: Cow<'_, PatternStr> = Cow::Owned(pattern);
|
|
let qualified: QualifiedPattern = unsafe { transmute(cow) };
|
|
|
|
qualified
|
|
}
|
|
}};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
#[test]
|
|
fn refname() {
|
|
let _ = crate::refname!("refs/heads/main");
|
|
let _ = crate::refname!("refs/tags/v1.0.0");
|
|
let _ = crate::refname!("refs/remotes/origin/main");
|
|
let _ = crate::refname!("a");
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn refname_invalid() {
|
|
let _ = crate::refname!("a~b");
|
|
}
|
|
|
|
#[test]
|
|
fn qualified() {
|
|
let _ = crate::qualified!("refs/heads/main");
|
|
let _ = crate::qualified!("refs/tags/v1.0.0");
|
|
let _ = crate::qualified!("refs/remotes/origin/main");
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn qualified_invalid() {
|
|
let _ = crate::qualified!("a");
|
|
}
|
|
|
|
#[test]
|
|
fn component() {
|
|
let _ = crate::component!("a");
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn component_invalid() {
|
|
let _ = crate::component!("a/b");
|
|
}
|
|
|
|
#[test]
|
|
fn pattern() {
|
|
let _ = crate::pattern!("refs/heads/main");
|
|
let _ = crate::pattern!("refs/tags/v1.0.0");
|
|
let _ = crate::pattern!("refs/remotes/origin/main");
|
|
|
|
let _ = crate::pattern!("a");
|
|
let _ = crate::pattern!("a/*");
|
|
let _ = crate::pattern!("*");
|
|
let _ = crate::pattern!("a/b*");
|
|
let _ = crate::pattern!("a/b*/c");
|
|
let _ = crate::pattern!("a/*/c");
|
|
}
|
|
|
|
#[test]
|
|
fn qualified_pattern() {
|
|
let _ = crate::qualified_pattern!("refs/heads/main");
|
|
let _ = crate::qualified_pattern!("refs/tags/v1.0.0");
|
|
let _ = crate::qualified_pattern!("refs/remotes/origin/main");
|
|
|
|
let _ = crate::qualified_pattern!("refs/heads/main/*");
|
|
let _ = crate::qualified_pattern!("refs/tags/v*");
|
|
let _ = crate::qualified_pattern!("refs/remotes/origin/main");
|
|
let _ = crate::qualified_pattern!("refs/remotes/origin/department/*/person");
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn qualified_pattern_invalid() {
|
|
let _ = crate::qualified_pattern!("a/*/b");
|
|
}
|
|
}
|