use crate::serializer::{InventorySerializer, RevisionSerializer};
use super::pack_2a::{RepositoryError, SharedTransport};
use super::Repository;
pub type OpenFn = fn(SharedTransport) -> Result<Box<dyn Repository>, RepositoryError>;
pub fn open_unsupported(
_transport: SharedTransport,
) -> Result<Box<dyn Repository>, RepositoryError> {
Err(RepositoryError::UnsupportedFormat("unsupported format"))
}
pub type CreateFn =
fn(&'static RepositoryFormat, SharedTransport) -> Result<Box<dyn Repository>, RepositoryError>;
pub fn create_unsupported(
_format: &'static RepositoryFormat,
_transport: SharedTransport,
) -> Result<Box<dyn Repository>, RepositoryError> {
Err(RepositoryError::UnsupportedFormat("unsupported format"))
}
pub struct RepositoryFormat {
pub format_string: &'static [u8],
pub description: &'static str,
pub open: OpenFn,
pub create: CreateFn,
pub revision_serializer: &'static dyn RevisionSerializer,
pub inventory_serializer: &'static dyn InventorySerializer,
pub rich_root_data: bool,
pub supports_chks: bool,
pub supports_tree_reference: bool,
pub supports_external_lookups: bool,
pub uses_btree_index: bool,
pub supported: bool,
pub deprecated: bool,
pub all_in_one: bool,
}
impl RepositoryFormat {
pub const DEFAULT: RepositoryFormat = RepositoryFormat {
format_string: b"",
description: "",
open: open_unsupported,
create: create_unsupported,
revision_serializer: &crate::bencode_serializer::BEncodeRevisionSerializer1,
inventory_serializer: &crate::xml_serializer::Chk255BigPageInventorySerializer,
rich_root_data: false,
supports_chks: false,
supports_tree_reference: false,
supports_external_lookups: false,
uses_btree_index: true,
supported: false,
deprecated: false,
all_in_one: false,
};
pub fn format_string(&self) -> &'static [u8] {
self.format_string
}
pub fn get_format_description(&self) -> &'static str {
self.description
}
pub fn is_supported(&self) -> bool {
self.supported
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
pub fn is_all_in_one(&self) -> bool {
self.all_in_one
}
pub fn network_name(&self) -> &'static [u8] {
self.format_string
}
}
pub struct RepositoryFormatRegistration(pub &'static RepositoryFormat);
inventory::collect!(RepositoryFormatRegistration);
#[macro_export]
macro_rules! declare_repository_format {
(
$name:ident {
format_string: $fmt:expr,
description: $desc:expr,
revision_serializer: $rev:expr,
inventory_serializer: $inv:expr,
$( $field:ident : $value:expr, )*
}
) => {
pub static $name: $crate::repository::format::RepositoryFormat =
$crate::repository::format::RepositoryFormat {
format_string: $fmt,
description: $desc,
revision_serializer: $rev,
inventory_serializer: $inv,
$( $field: $value, )*
..$crate::repository::format::RepositoryFormat::DEFAULT
};
inventory::submit! {
$crate::repository::format::RepositoryFormatRegistration(&$name)
}
};
}
pub fn find_format(format_string: &[u8]) -> Option<&'static RepositoryFormat> {
inventory::iter::<RepositoryFormatRegistration>
.into_iter()
.map(|r| r.0)
.find(|f| f.format_string == format_string)
}
pub fn all_formats() -> Vec<&'static RepositoryFormat> {
inventory::iter::<RepositoryFormatRegistration>
.into_iter()
.map(|r| r.0)
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_2a_format_is_registered_and_supported() {
let f = find_format(b"Bazaar repository format 2a (needs bzr 1.16 or later)\n")
.expect("2a format registered");
assert!(std::ptr::fn_addr_eq(
f.open,
super::super::pack_2a::open_group_compress as OpenFn
));
assert!(f.supports_chks);
assert!(f.rich_root_data);
assert!(f.is_supported());
}
#[cfg(feature = "knitpack")]
#[test]
fn knitpack_formats_are_registered() {
let f = find_format(b"Bazaar pack repository format 1 (needs bzr 0.92)\n")
.expect("knitpack 1 registered");
assert!(std::ptr::fn_addr_eq(
f.open,
super::super::pack_knit::open_knit_pack as OpenFn
));
assert!(!f.rich_root_data);
assert_eq!(f.inventory_serializer.format_num(), b"5");
}
#[cfg(feature = "knitpack")]
#[test]
fn rich_root_knitpack_uses_xml6() {
let f = find_format(b"Bazaar pack repository format 1 with rich root (needs bzr 1.0)\n")
.expect("knitpack 4 registered");
assert!(f.rich_root_data);
assert_eq!(f.inventory_serializer.format_num(), b"6");
}
#[test]
fn unknown_marker_is_none() {
assert!(find_format(b"Bazaar nonsense format\n").is_none());
}
#[test]
fn the_always_on_2a_format_is_present() {
assert!(find_format(b"Bazaar repository format 2a (needs bzr 1.16 or later)\n").is_some());
assert!(!all_formats().is_empty());
}
}