use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use byteorder::BigEndian;
use mmap_rs::Mmap;
use crate::mph::LoadableSwhidMphf;
use crate::utils::mmap::NumberMmap;
use crate::utils::GetIndex;
use crate::OutOfBoundError;
pub(crate) mod suffixes {
pub const NODE2SWHID: &str = ".node2swhid.bin";
pub const NODE2TYPE: &str = ".node2type.bin";
pub const AUTHOR_TIMESTAMP: &str = ".property.author_timestamp.bin";
pub const AUTHOR_TIMESTAMP_OFFSET: &str = ".property.author_timestamp_offset.bin";
pub const COMMITTER_TIMESTAMP: &str = ".property.committer_timestamp.bin";
pub const COMMITTER_TIMESTAMP_OFFSET: &str = ".property.committer_timestamp_offset.bin";
pub const AUTHOR_ID: &str = ".property.author_id.bin";
pub const COMMITTER_ID: &str = ".property.committer_id.bin";
pub const CONTENT_IS_SKIPPED: &str = ".property.content.is_skipped.bits";
pub const CONTENT_LENGTH: &str = ".property.content.length.bin";
pub const MESSAGE: &str = ".property.message.bin";
pub const MESSAGE_OFFSET: &str = ".property.message.offset.bin";
pub const TAG_NAME: &str = ".property.tag_name.bin";
pub const TAG_NAME_OFFSET: &str = ".property.tag_name.offset.bin";
pub const LABEL_NAME: &str = ".labels.fcl";
}
#[derive(thiserror::Error, Debug)]
#[error("{path} cannot be loaded: {source}")]
pub struct UnavailableProperty {
path: PathBuf,
#[source]
source: std::io::Error,
}
pub type PropertiesResult<'err, T, B> =
<<B as PropertiesBackend>::DataFilesAvailability as DataFilesAvailability>::Result<'err, T>;
pub trait PropertiesBackend {
type DataFilesAvailability: DataFilesAvailability;
fn map_if_available<T, U>(
v: <Self::DataFilesAvailability as DataFilesAvailability>::Result<'_, T>,
f: impl FnOnce(T) -> U,
) -> <Self::DataFilesAvailability as DataFilesAvailability>::Result<'_, U> {
<Self::DataFilesAvailability as DataFilesAvailability>::map(v, f)
}
fn zip_if_available<'err, T1, T2>(
v1: <Self::DataFilesAvailability as DataFilesAvailability>::Result<'err, T1>,
v2: <Self::DataFilesAvailability as DataFilesAvailability>::Result<'err, T2>,
) -> <Self::DataFilesAvailability as DataFilesAvailability>::Result<'err, (T1, T2)> {
<Self::DataFilesAvailability as DataFilesAvailability>::zip(v1, v2)
}
}
pub trait DataFilesAvailability {
type Result<'err, T>;
fn map<T, U>(v: Self::Result<'_, T>, f: impl FnOnce(T) -> U) -> Self::Result<'_, U>;
fn zip<'err, T1, T2>(
v1: Self::Result<'err, T1>,
v2: Self::Result<'err, T2>,
) -> Self::Result<'err, (T1, T2)>;
fn make_result<T>(value: Self::Result<'_, T>) -> Result<T, &UnavailableProperty>;
}
pub struct OptionalDataFiles {
_marker: (), }
pub struct GuaranteedDataFiles {
_marker: (), }
impl DataFilesAvailability for OptionalDataFiles {
type Result<'err, T> = Result<T, &'err UnavailableProperty>;
#[inline(always)]
fn map<T, U>(v: Self::Result<'_, T>, f: impl FnOnce(T) -> U) -> Self::Result<'_, U> {
v.map(f)
}
#[inline(always)]
fn zip<'err, T1, T2>(
v1: Self::Result<'err, T1>,
v2: Self::Result<'err, T2>,
) -> Self::Result<'err, (T1, T2)> {
v1.and_then(|v1| v2.map(|v2| (v1, v2)))
}
#[inline(always)]
fn make_result<T>(value: Self::Result<'_, T>) -> Result<T, &UnavailableProperty> {
value
}
}
impl DataFilesAvailability for GuaranteedDataFiles {
type Result<'err, T> = T;
#[inline(always)]
fn map<T, U>(v: Self::Result<'_, T>, f: impl FnOnce(T) -> U) -> Self::Result<'_, U> {
f(v)
}
#[inline(always)]
fn zip<'err, T1, T2>(
v1: Self::Result<'err, T1>,
v2: Self::Result<'err, T2>,
) -> Self::Result<'err, (T1, T2)> {
(v1, v2)
}
#[inline(always)]
fn make_result<T>(value: Self::Result<'_, T>) -> Result<T, &UnavailableProperty> {
Ok(value)
}
}
pub struct SwhGraphProperties<
MAPS: MaybeMaps,
TIMESTAMPS: MaybeTimestamps,
PERSONS: MaybePersons,
CONTENTS: MaybeContents,
STRINGS: MaybeStrings,
LABELNAMES: MaybeLabelNames,
> {
pub(crate) path: PathBuf,
pub(crate) num_nodes: usize,
pub(crate) maps: MAPS,
pub(crate) timestamps: TIMESTAMPS,
pub(crate) persons: PERSONS,
pub(crate) contents: CONTENTS,
pub(crate) strings: STRINGS,
pub(crate) label_names: LABELNAMES,
pub(crate) label_names_are_in_base64_order: once_cell::race::OnceBool,
}
pub type AllSwhGraphProperties<MPHF> = SwhGraphProperties<
MappedMaps<MPHF>,
MappedTimestamps,
MappedPersons,
MappedContents,
MappedStrings,
MappedLabelNames,
>;
pub type AllSwhGraphDynProperties<MPHF> = SwhGraphProperties<
MappedMaps<MPHF>,
OptMappedTimestamps,
OptMappedPersons,
OptMappedContents,
OptMappedStrings,
MappedLabelNames,
>;
impl SwhGraphProperties<NoMaps, NoTimestamps, NoPersons, NoContents, NoStrings, NoLabelNames> {
pub fn new(path: impl AsRef<Path>, num_nodes: usize) -> Self {
SwhGraphProperties {
path: path.as_ref().to_owned(),
num_nodes,
maps: NoMaps,
timestamps: NoTimestamps,
persons: NoPersons,
contents: NoContents,
strings: NoStrings,
label_names: NoLabelNames,
label_names_are_in_base64_order: Default::default(),
}
}
pub fn load_all<MPHF: LoadableSwhidMphf>(self) -> Result<AllSwhGraphProperties<MPHF>> {
self.load_maps()?
.load_timestamps()?
.load_persons()?
.load_contents()?
.load_strings()?
.load_label_names()
}
}
mod maps;
pub use maps::{MappedMaps, Maps, MaybeMaps, NoMaps, NodeIdFromSwhidError, VecMaps};
mod timestamps;
pub use timestamps::{
MappedTimestamps, MaybeTimestamps, NoTimestamps, OptMappedTimestamps, OptTimestamps,
Timestamps, VecTimestamps,
};
mod persons;
pub use persons::{
MappedPersons, MaybePersons, NoPersons, OptMappedPersons, OptPersons, Persons, VecPersons,
};
mod contents;
pub use contents::{
Contents, MappedContents, MaybeContents, NoContents, OptContents, OptMappedContents,
VecContents,
};
mod strings;
pub use strings::{
MappedStrings, MaybeStrings, NoStrings, OptMappedStrings, OptStrings, Strings, VecStrings,
};
mod label_names;
pub use label_names::{
LabelIdFromNameError, LabelNames, MappedLabelNames, MaybeLabelNames, NoLabelNames,
VecLabelNames,
};
mod utils;
use utils::*;