git-ref-format: New crate
For further details on the crate see its documentation in `crates/radicle-git-ref-format/src/lib.rs`.
This commit is contained in:
parent
292befdb36
commit
3fcf2a86da
|
|
@ -2914,6 +2914,13 @@ dependencies = [
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radicle-git-ref-format"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"git-ref-format-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "radicle-node"
|
name = "radicle-node"
|
||||||
version = "0.16.0"
|
version = "0.16.0"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "radicle-git-ref-format"
|
||||||
|
description = "Radicle re-exports and macros for `git-ref-format-core`"
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
version = "0.1.0"
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
keywords = ["radicle", "git", "refname", "ref", "references"]
|
||||||
|
rust-version.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
macro = []
|
||||||
|
bstr = ["git-ref-format-core/bstr"]
|
||||||
|
serde = ["git-ref-format-core/serde"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
git-ref-format-core.workspace = true
|
||||||
|
|
@ -0,0 +1,298 @@
|
||||||
|
#![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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue