Move data
crate to its own repo
I suspect that the `data` crate will get more review, use, and contributors if it lives in its own repository, so move it to casey/data. type: removed
This commit is contained in:
parent
173c0e5ac5
commit
c1c8d3cb89
81
Cargo.lock
generated
81
Cargo.lock
generated
|
@ -181,15 +181,6 @@ dependencies = [
|
|||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "claim"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b2e893ee68bf12771457cceea72497bc9cb7da404ec8a5311226d354b895ba4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
|
@ -199,7 +190,7 @@ dependencies = [
|
|||
"ansi_term 0.11.0",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"strsim",
|
||||
"term_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
|
@ -257,66 +248,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1"
|
||||
checksum = "cf6b25ee9ac1995c54d7adb2eff8cfffb7260bc774fb63c601ec65467f43cd9d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.9.3",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "data-macros"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "demo"
|
||||
version = "0.0.0"
|
||||
|
@ -510,12 +449,6 @@ dependencies = [
|
|||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.0"
|
||||
|
@ -554,7 +487,6 @@ dependencies = [
|
|||
"atty",
|
||||
"bendy",
|
||||
"chrono",
|
||||
"claim",
|
||||
"console",
|
||||
"globset",
|
||||
"ignore",
|
||||
|
@ -578,7 +510,6 @@ dependencies = [
|
|||
"structopt",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"temptree",
|
||||
"unicode-width",
|
||||
|
@ -1097,12 +1028,6 @@ version = "0.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.3.14"
|
||||
|
|
|
@ -36,7 +36,6 @@ snafu = "0.6.0"
|
|||
static_assertions = "1.0.0"
|
||||
strum = "0.18.0"
|
||||
strum_macros = "0.18.0"
|
||||
syn = "1.0.14"
|
||||
tempfile = "3.0.0"
|
||||
unicode-width = "0.1.0"
|
||||
|
||||
|
@ -61,7 +60,6 @@ version = "2.1.1"
|
|||
features = ["serde"]
|
||||
|
||||
[dev-dependencies]
|
||||
claim = "0.3.1"
|
||||
temptree = "0.0.0"
|
||||
|
||||
[workspace]
|
||||
|
@ -71,10 +69,4 @@ members = [
|
|||
|
||||
# run commands for demo animation
|
||||
"bin/demo",
|
||||
|
||||
# data description language
|
||||
"crates/data",
|
||||
|
||||
# data description language proc macros
|
||||
"crates/data-macros",
|
||||
]
|
||||
|
|
|
@ -27,6 +27,7 @@ pub(crate) enum Kind {
|
|||
Reform,
|
||||
Release,
|
||||
Testing,
|
||||
Removed,
|
||||
}
|
||||
|
||||
impl Kind {
|
||||
|
@ -43,6 +44,7 @@ impl Kind {
|
|||
Self::Reform => "🎨",
|
||||
Self::Release => "🔖",
|
||||
Self::Testing => "✅",
|
||||
Self::Removed => "➖",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +61,7 @@ impl Kind {
|
|||
Self::Reform => ":art:",
|
||||
Self::Release => ":bookmark:",
|
||||
Self::Testing => ":white_check_mark:",
|
||||
Self::Removed => ":heavy_minus_sign:",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
[package]
|
||||
name = "data-macros"
|
||||
version = "0.0.0"
|
||||
authors = ["Casey Rodarmor <casey@rodarmor.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
darling = "0.10.2"
|
||||
proc-macro2 = "1.0.12"
|
||||
quote = "1.0.4"
|
||||
syn = "1.0.18"
|
|
@ -1,28 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
pub(crate) trait Attribute: FromMeta {
|
||||
type Item: syn::parse::Parse;
|
||||
|
||||
fn attribute(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
Self::inner(attr.into(), item.into()).tokens().into()
|
||||
}
|
||||
|
||||
fn inner(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Error> {
|
||||
let args = Punctuated::<NestedMeta, token::Comma>::parse_terminated
|
||||
.parse2(attr)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
Self::innermost(args, item)
|
||||
}
|
||||
|
||||
fn innermost(args: Vec<NestedMeta>, item: TokenStream) -> Result<TokenStream, Error> {
|
||||
let item = syn::parse2::<Self::Item>(item)?;
|
||||
Self::from_list(&args)?.expand(item)
|
||||
}
|
||||
|
||||
fn expand(&self, item: Self::Item) -> Result<TokenStream, Error>;
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
pub(crate) use darling::FromMeta;
|
||||
pub(crate) use proc_macro2::TokenStream;
|
||||
pub(crate) use quote::ToTokens;
|
||||
pub(crate) use syn::{parse::Parser, punctuated::Punctuated, token, ItemTrait, NestedMeta};
|
||||
|
||||
pub(crate) use crate::{attribute::Attribute, tokens::Tokens};
|
||||
|
||||
pub(crate) use crate::{error::Error, table::Table};
|
|
@ -1,28 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Error {
|
||||
Parse(darling::Error),
|
||||
Syn(syn::Error),
|
||||
}
|
||||
|
||||
impl From<darling::Error> for Error {
|
||||
fn from(error: darling::Error) -> Error {
|
||||
Error::Parse(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<syn::Error> for Error {
|
||||
fn from(error: syn::Error) -> Error {
|
||||
Error::Syn(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokens for Error {
|
||||
fn tokens(self) -> TokenStream {
|
||||
match self {
|
||||
Error::Parse(error) => error.write_errors(),
|
||||
Error::Syn(error) => error.to_compile_error(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
mod test;
|
||||
|
||||
mod attribute;
|
||||
mod common;
|
||||
mod error;
|
||||
mod table;
|
||||
mod tokens;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn table(
|
||||
attr: proc_macro::TokenStream,
|
||||
item: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
Table::attribute(attr, item)
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
#[derive(FromMeta)]
|
||||
pub(crate) struct Table {}
|
||||
|
||||
impl Attribute for Table {
|
||||
type Item = ItemTrait;
|
||||
|
||||
fn expand(&self, item: Self::Item) -> Result<TokenStream, Error> {
|
||||
Ok(item.into_token_stream())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn empty() {
|
||||
assert_attribute_expansion_eq!(
|
||||
#[data::table]
|
||||
trait Foo {},
|
||||
trait Foo {}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
use syn::{Meta, MetaNameValue, NestedMeta};
|
||||
|
||||
macro_rules! assert_attribute_expansion_eq {
|
||||
{
|
||||
#[$meta:meta]
|
||||
$item:item,
|
||||
$($expansion:tt)*
|
||||
} => {
|
||||
{
|
||||
let have = expand_attribute!(#[$meta] $item).unwrap().to_string();
|
||||
let want = quote::quote!($($expansion)*).to_string();
|
||||
assert_eq!(have, want);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! expand_attribute {
|
||||
{
|
||||
#[$meta:meta]
|
||||
$item:item
|
||||
} => {
|
||||
{
|
||||
let meta = quote::quote!($meta);
|
||||
let item = quote::quote!($item);
|
||||
$crate::test::expand_attribute(meta, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn expand_attribute(meta: TokenStream, item: TokenStream) -> Result<TokenStream, Error> {
|
||||
let meta = syn::parse2::<Meta>(meta).unwrap();
|
||||
|
||||
let (path, args) = split_meta(meta);
|
||||
|
||||
match path.as_str() {
|
||||
"data::table" => Table::innermost(args, item),
|
||||
_ => panic!("attribute `{}` unknown", path),
|
||||
}
|
||||
}
|
||||
|
||||
fn split_meta(meta: Meta) -> (String, Vec<NestedMeta>) {
|
||||
fn text(path: syn::Path) -> String {
|
||||
let mut text = String::new();
|
||||
|
||||
if let Some(_) = path.leading_colon {
|
||||
text.push_str("::");
|
||||
}
|
||||
|
||||
for (i, segment) in path.segments.iter().enumerate() {
|
||||
if i > 0 {
|
||||
text.push_str("::");
|
||||
}
|
||||
text.push_str(&segment.ident.to_string());
|
||||
}
|
||||
|
||||
text
|
||||
}
|
||||
|
||||
match meta {
|
||||
Meta::Path(path) => (text(path), Vec::new()),
|
||||
Meta::List(syn::MetaList { path, nested, .. }) => (text(path), nested.into_iter().collect()),
|
||||
Meta::NameValue(MetaNameValue { path, lit, .. }) => (text(path), vec![NestedMeta::Lit(lit)]),
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
pub(crate) trait Tokens {
|
||||
fn tokens(self) -> TokenStream;
|
||||
}
|
||||
|
||||
impl Tokens for TokenStream {
|
||||
fn tokens(self) -> TokenStream {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Tokens, E: Tokens> Tokens for Result<T, E> {
|
||||
fn tokens(self) -> TokenStream {
|
||||
match self {
|
||||
Ok(t) => t.tokens(),
|
||||
Err(e) => e.tokens(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[package]
|
||||
name = "data"
|
||||
version = "0.1.0"
|
||||
authors = ["Casey Rodarmor <casey@rodarmor.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies.data-macros]
|
||||
path = "../data-macros"
|
|
@ -1,36 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
pub(crate) struct Buffer {
|
||||
layout: Layout,
|
||||
alloc: *mut u8,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub(crate) fn new<'a, T: Data<'a>>(contents: &[u8]) -> Buffer {
|
||||
let layout = Layout::from_size_align(T::FIXED_SIZE, T::ALIGNMENT).unwrap();
|
||||
let alloc = unsafe { alloc::alloc::alloc_zeroed(layout) };
|
||||
let mut buffer = Buffer { layout, alloc };
|
||||
buffer.deref_mut().copy_from_slice(contents);
|
||||
buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe { alloc::alloc::dealloc(self.alloc, self.layout) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Buffer {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { core::slice::from_raw_parts(self.alloc, self.layout.size()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Buffer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { core::slice::from_raw_parts_mut(self.alloc, self.layout.size()) }
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
pub(crate) use core::{result, str::Utf8Error};
|
||||
|
||||
pub(crate) use crate::error::Error;
|
||||
|
||||
pub(crate) use crate::data::Data;
|
||||
|
||||
pub(crate) type Result<T, E = Error> = result::Result<T, E>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
pub(crate) extern crate alloc;
|
||||
|
||||
pub(crate) use core::{
|
||||
fmt::Debug,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
pub(crate) use alloc::{alloc::Layout, vec::Vec};
|
||||
|
||||
pub(crate) use crate::buffer::Buffer;
|
||||
|
||||
pub(crate) use crate::data_test::DataTest;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use test::*;
|
|
@ -1,27 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
pub trait Data<'a>: Sized + 'a {
|
||||
const FIXED_SIZE: usize;
|
||||
|
||||
const ALIGNMENT: usize;
|
||||
|
||||
fn load(buffer: &'a [u8]) -> Result<Self>;
|
||||
|
||||
fn store(&self, buffer: &mut [u8]) -> Result<()>;
|
||||
|
||||
fn check(buffer: &'a [u8]) -> Result<()> {
|
||||
let have = buffer.len();
|
||||
let want = Self::FIXED_SIZE;
|
||||
if have < want {
|
||||
return Err(Error::Size { have, want });
|
||||
}
|
||||
|
||||
let alignment = Self::ALIGNMENT;
|
||||
let offset = buffer.as_ptr().align_offset(alignment);
|
||||
if offset != 0 {
|
||||
return Err(Error::Alignment { alignment, offset });
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
pub trait DataTest<'a>: Data<'a> + PartialEq + Debug + Default {
|
||||
fn round_trip(self, encoded: &'a [u8]) -> Result<()> {
|
||||
let mut buffer = Vec::<u8>::with_capacity(Self::FIXED_SIZE);
|
||||
buffer.resize(Self::FIXED_SIZE, 0);
|
||||
self.store(&mut buffer)?;
|
||||
assert_eq!(buffer, encoded);
|
||||
let decoded = Self::load(&encoded)?;
|
||||
assert_eq!(self, decoded);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn error_test(buffer: &'a mut [u8]) {
|
||||
let want = Self::FIXED_SIZE;
|
||||
let have = Self::FIXED_SIZE - 1;
|
||||
assert_eq!(buffer.len(), want);
|
||||
let short_buffer = &mut buffer[..have];
|
||||
assert_eq!(
|
||||
Self::default().store(short_buffer),
|
||||
Err(Error::Size { have, want })
|
||||
);
|
||||
assert_eq!(Self::load(short_buffer), Err(Error::Size { have, want }));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Data<'a> + PartialEq + Debug + Default> DataTest<'a> for T {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn round_trip_test() {
|
||||
0u8.round_trip(&[1]).ok();
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
Alignment { alignment: usize, offset: usize },
|
||||
UnicodeDecode { source: Utf8Error },
|
||||
Size { have: usize, want: usize },
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
#![no_std]
|
||||
|
||||
mod common;
|
||||
mod data;
|
||||
mod error;
|
||||
mod u16;
|
||||
mod u8;
|
||||
|
||||
#[cfg(test)]
|
||||
mod buffer;
|
||||
|
||||
#[cfg(test)]
|
||||
mod data_test;
|
||||
|
||||
pub use data_macros::table;
|
||||
|
||||
pub use crate::{data::Data, error::Error};
|
|
@ -1,38 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
impl<'a> Data<'a> for u16 {
|
||||
const ALIGNMENT: usize = 2;
|
||||
const FIXED_SIZE: usize = 2;
|
||||
|
||||
fn load(buffer: &'a [u8]) -> Result<Self> {
|
||||
Self::check(buffer)?;
|
||||
Ok(u16::from_le_bytes([buffer[0], buffer[1]]))
|
||||
}
|
||||
|
||||
fn store(&self, buffer: &mut [u8]) -> Result<()> {
|
||||
Self::check(buffer)?;
|
||||
let bytes = self.to_le_bytes();
|
||||
buffer.copy_from_slice(&bytes);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn u16_round_trip() -> Result<()> {
|
||||
0u16.round_trip(&Buffer::new::<u16>(&[0, 0]))?;
|
||||
1u16.round_trip(&Buffer::new::<u16>(&[1, 0]))?;
|
||||
255u16.round_trip(&Buffer::new::<u16>(&[255, 0]))?;
|
||||
256u16.round_trip(&Buffer::new::<u16>(&[0, 1]))?;
|
||||
u16::max_value().round_trip(&Buffer::new::<u16>(&[0xFF, 0xFF]))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u16_errors() {
|
||||
u16::error_test(&mut Buffer::new::<u16>(&[0, 0]));
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
use crate::common::*;
|
||||
|
||||
impl<'a> Data<'a> for u8 {
|
||||
const ALIGNMENT: usize = 1;
|
||||
const FIXED_SIZE: usize = 1;
|
||||
|
||||
fn load(buffer: &'a [u8]) -> Result<Self> {
|
||||
Self::check(buffer)?;
|
||||
Ok(buffer[0])
|
||||
}
|
||||
|
||||
fn store(&self, buffer: &mut [u8]) -> Result<()> {
|
||||
Self::check(buffer)?;
|
||||
buffer[0] = *self;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn u8_round_trip() -> Result<()> {
|
||||
0u8.round_trip(&[0])?;
|
||||
1u8.round_trip(&[1])?;
|
||||
255u8.round_trip(&[255])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u8_errors() {
|
||||
u8::error_test(&mut Buffer::new::<u8>(&[0]));
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#[cfg(aspirational)]
|
||||
mod aspirational {
|
||||
|
||||
#[data::structure]
|
||||
struct Manifest {
|
||||
magic_number: [u8; 8], // IMDL + 4 bytes that aren't valid UTF-8
|
||||
version: Version, // 256.256.256
|
||||
}
|
||||
|
||||
#[data::structure]
|
||||
struct Version {
|
||||
major: u64,
|
||||
minor: u64,
|
||||
patch: u64,
|
||||
}
|
||||
|
||||
#[data::table]
|
||||
struct Manifest;
|
||||
|
||||
#[data::table_impl]
|
||||
impl Manifest {
|
||||
fn files(&self) -> Slice<Hash>;
|
||||
|
||||
fn directory(&self) -> Directory;
|
||||
}
|
||||
|
||||
#[data::structure]
|
||||
struct Directory {
|
||||
records: Slice<Record>,
|
||||
}
|
||||
|
||||
#[data::structure]
|
||||
struct Record {
|
||||
name: &str,
|
||||
node: Node,
|
||||
}
|
||||
|
||||
#[data::enumeration]
|
||||
enum Node {
|
||||
Directory(Directory),
|
||||
File(u64),
|
||||
}
|
||||
|
||||
#[data::structure]
|
||||
struct Hash {
|
||||
bytes: [u8; 32],
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user