mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 00:45:18 +03:00
blobstore: export impl_loadable_storable macro
Summary: This will help people to introduce new blobstore objects in their code (for instance I intend to use it in the following diff). The `private` module exists to allow the use of the exported macro without the need to write a bunch of `use` statements, and without pollution the re-export namespace. The idea is that everything needed by the exported macro exists in the `private` module of the crate, and this module is public. So long as some other crate imports the macro, it expands to `$crate::private::NEEDED_THING` in the right places and no further `use` statements of dependencies are needed. At the same time, the name `private` should discourage people from using whatever is in this module directly. The idea is taken from `anyhow`. Reviewed By: StanislavGlebik Differential Revision: D27997228 fbshipit-source-id: fd2c421d0daf0fe88e2b9001bb4088fe7b4d59b7
This commit is contained in:
parent
fbdd7a453c
commit
82ffc5b731
@ -17,6 +17,7 @@ async-trait = "0.1.45"
|
|||||||
auto_impl = "0.4"
|
auto_impl = "0.4"
|
||||||
bytes = { version = "0.5", features = ["serde"] }
|
bytes = { version = "0.5", features = ["serde"] }
|
||||||
context = { version = "0.1.0", path = "../server/context" }
|
context = { version = "0.1.0", path = "../server/context" }
|
||||||
|
fbthrift = { version = "0.0.1+unstable", git = "https://github.com/facebook/fbthrift.git", branch = "master" }
|
||||||
futures-old = { package = "futures", version = "0.1.31" }
|
futures-old = { package = "futures", version = "0.1.31" }
|
||||||
serde = { version = "=1.0.118", features = ["derive", "rc"] }
|
serde = { version = "=1.0.118", features = ["derive", "rc"] }
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
mod counted_blobstore;
|
mod counted_blobstore;
|
||||||
mod disabled;
|
mod disabled;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
use abomonation_derive::Abomonation;
|
use abomonation_derive::Abomonation;
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
@ -29,6 +30,20 @@ pub use crate::counted_blobstore::CountedBlobstore;
|
|||||||
pub use crate::disabled::DisabledBlob;
|
pub use crate::disabled::DisabledBlob;
|
||||||
pub use crate::errors::ErrorKind;
|
pub use crate::errors::ErrorKind;
|
||||||
|
|
||||||
|
// This module exists to namespace re-exported
|
||||||
|
// imports, needed for macto exports.
|
||||||
|
pub mod private {
|
||||||
|
pub use crate::{
|
||||||
|
Blobstore, BlobstoreBytes, BlobstoreGetData, Loadable, LoadableError, Storable,
|
||||||
|
};
|
||||||
|
pub use anyhow::Error;
|
||||||
|
pub use async_trait::async_trait;
|
||||||
|
pub use context::CoreContext;
|
||||||
|
pub use fbthrift::compact_protocol;
|
||||||
|
pub use std::convert::TryFrom;
|
||||||
|
pub use std::convert::TryInto;
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct BlobstoreGetData {
|
pub struct BlobstoreGetData {
|
||||||
meta: BlobstoreMetadata,
|
meta: BlobstoreMetadata,
|
||||||
|
107
eden/mononoke/blobstore/src/macros.rs
Normal file
107
eden/mononoke/blobstore/src/macros.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This software may be used and distributed according to the terms of the
|
||||||
|
* GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_blobstore_conversions {
|
||||||
|
($ty:ident, $thrift_ty:ident) => {
|
||||||
|
impl $crate::private::TryFrom<$crate::private::BlobstoreBytes> for $ty {
|
||||||
|
type Error = $crate::private::Error;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
bytes: $crate::private::BlobstoreBytes,
|
||||||
|
) -> Result<Self, $crate::private::Error> {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
let t: $thrift_ty =
|
||||||
|
$crate::private::compact_protocol::deserialize(bytes.as_bytes().as_ref())?;
|
||||||
|
t.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$ty> for $crate::private::BlobstoreBytes {
|
||||||
|
fn from(other: $ty) -> Self {
|
||||||
|
let thrift: $thrift_ty = other.into();
|
||||||
|
let data = $crate::private::compact_protocol::serialize(&thrift);
|
||||||
|
Self::from_bytes(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::private::TryFrom<$crate::private::BlobstoreGetData> for $ty {
|
||||||
|
type Error = $crate::private::Error;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
blob: $crate::private::BlobstoreGetData,
|
||||||
|
) -> Result<Self, $crate::private::Error> {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
blob.into_bytes().try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$ty> for $crate::private::BlobstoreGetData {
|
||||||
|
fn from(other: $ty) -> Self {
|
||||||
|
Into::<$crate::private::BlobstoreBytes>::into(other).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// You can use this macro under the following conditions:
|
||||||
|
/// 1. handle_thrift_type can be serialized into handle_type using thrift compact protocol
|
||||||
|
/// 2. value_thrift_type can be serialized into value_type using thrift compact protocol
|
||||||
|
/// 3. value_type has method `fn handle(&self) -> handle_type`
|
||||||
|
/// 4. handle_type has method `fb blobstore_key(&self) -> String`
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! impl_loadable_storable {
|
||||||
|
(
|
||||||
|
handle_type => $handle: ident,
|
||||||
|
handle_thrift_type => $thrift_handle: ident,
|
||||||
|
value_type => $ty:ident,
|
||||||
|
value_thrift_type => $thrift_ty: ident,
|
||||||
|
) => {
|
||||||
|
#[$crate::private::async_trait]
|
||||||
|
impl $crate::private::Storable for $ty {
|
||||||
|
type Key = $handle;
|
||||||
|
|
||||||
|
async fn store<'a, B: $crate::private::Blobstore>(
|
||||||
|
self,
|
||||||
|
ctx: &'a $crate::private::CoreContext,
|
||||||
|
blobstore: &'a B,
|
||||||
|
) -> Result<Self::Key, $crate::private::Error> {
|
||||||
|
let handle = *self.handle();
|
||||||
|
let key = handle.blobstore_key();
|
||||||
|
blobstore.put(ctx, key, self.into()).await?;
|
||||||
|
Ok(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[$crate::private::async_trait]
|
||||||
|
impl $crate::private::Loadable for $handle {
|
||||||
|
type Value = $ty;
|
||||||
|
|
||||||
|
async fn load<'a, B: $crate::private::Blobstore>(
|
||||||
|
&'a self,
|
||||||
|
ctx: &'a $crate::private::CoreContext,
|
||||||
|
blobstore: &'a B,
|
||||||
|
) -> Result<Self::Value, $crate::private::LoadableError> {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
let id = *self;
|
||||||
|
let bytes = blobstore.get(ctx, &id.blobstore_key()).await?;
|
||||||
|
match bytes {
|
||||||
|
Some(bytes) => bytes
|
||||||
|
.try_into()
|
||||||
|
.map_err($crate::private::LoadableError::Error),
|
||||||
|
None => Err($crate::private::LoadableError::Missing(id.blobstore_key())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::impl_blobstore_conversions!($handle, $thrift_handle);
|
||||||
|
$crate::impl_blobstore_conversions!($ty, $thrift_ty);
|
||||||
|
};
|
||||||
|
}
|
@ -14,7 +14,6 @@ cloned = { version = "0.1.0", git = "https://github.com/facebookexperimental/rus
|
|||||||
context = { version = "0.1.0", path = "../../server/context" }
|
context = { version = "0.1.0", path = "../../server/context" }
|
||||||
derived_data = { version = "0.1.0", path = "../../derived_data" }
|
derived_data = { version = "0.1.0", path = "../../derived_data" }
|
||||||
digest = "0.8"
|
digest = "0.8"
|
||||||
fbthrift = { version = "0.0.1+unstable", git = "https://github.com/facebook/fbthrift.git", branch = "master" }
|
|
||||||
filestore = { version = "0.1.0", path = "../../filestore" }
|
filestore = { version = "0.1.0", path = "../../filestore" }
|
||||||
futures = { version = "0.3.13", features = ["async-await", "compat"] }
|
futures = { version = "0.3.13", features = ["async-await", "compat"] }
|
||||||
futures_ext = { package = "futures_01_ext", version = "0.1.0", git = "https://github.com/facebookexperimental/rust-shed.git", branch = "master" }
|
futures_ext = { package = "futures_01_ext", version = "0.1.0", git = "https://github.com/facebookexperimental/rust-shed.git", branch = "master" }
|
||||||
|
@ -5,90 +5,14 @@
|
|||||||
* GNU General Public License version 2.
|
* GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use anyhow::Error;
|
use blobstore::impl_loadable_storable;
|
||||||
use async_trait::async_trait;
|
|
||||||
use blobstore::{Blobstore, BlobstoreBytes, BlobstoreGetData, Loadable, LoadableError, Storable};
|
|
||||||
use context::CoreContext;
|
|
||||||
use fbthrift::compact_protocol;
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
use crate::{thrift, Tree, TreeHandle};
|
use crate::thrift::{Tree as ThriftTree, TreeHandle as ThriftTreeHandle};
|
||||||
|
use crate::{Tree, TreeHandle};
|
||||||
|
|
||||||
macro_rules! impl_blobstore_conversions {
|
impl_loadable_storable! {
|
||||||
($ty:ident) => {
|
handle_type => TreeHandle,
|
||||||
impl TryFrom<BlobstoreBytes> for $ty {
|
handle_thrift_type => ThriftTreeHandle,
|
||||||
type Error = Error;
|
value_type => Tree,
|
||||||
|
value_thrift_type => ThriftTree,
|
||||||
fn try_from(bytes: BlobstoreBytes) -> Result<Self, Error> {
|
|
||||||
let t: thrift::$ty = compact_protocol::deserialize(bytes.as_bytes().as_ref())?;
|
|
||||||
t.try_into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<BlobstoreBytes> for $ty {
|
|
||||||
fn into(self) -> BlobstoreBytes {
|
|
||||||
let thrift: thrift::$ty = self.into();
|
|
||||||
let data = compact_protocol::serialize(&thrift);
|
|
||||||
BlobstoreBytes::from_bytes(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<BlobstoreGetData> for $ty {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(blob: BlobstoreGetData) -> Result<Self, Error> {
|
|
||||||
blob.into_bytes().try_into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<BlobstoreGetData> for $ty {
|
|
||||||
fn into(self) -> BlobstoreGetData {
|
|
||||||
Into::<BlobstoreBytes>::into(self).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_loadable_storable {
|
|
||||||
($handle: ident, $ty:ident) => {
|
|
||||||
#[async_trait]
|
|
||||||
impl Storable for $ty {
|
|
||||||
type Key = $handle;
|
|
||||||
|
|
||||||
async fn store<'a, B: Blobstore>(
|
|
||||||
self,
|
|
||||||
ctx: &'a CoreContext,
|
|
||||||
blobstore: &'a B,
|
|
||||||
) -> Result<Self::Key, Error> {
|
|
||||||
let handle = *self.handle();
|
|
||||||
let key = handle.blobstore_key();
|
|
||||||
blobstore.put(ctx, key, self.into()).await?;
|
|
||||||
Ok(handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl Loadable for $handle {
|
|
||||||
type Value = $ty;
|
|
||||||
|
|
||||||
async fn load<'a, B: Blobstore>(
|
|
||||||
&'a self,
|
|
||||||
ctx: &'a CoreContext,
|
|
||||||
blobstore: &'a B,
|
|
||||||
) -> Result<Self::Value, LoadableError> {
|
|
||||||
let id = *self;
|
|
||||||
let bytes = blobstore.get(ctx, &id.blobstore_key()).await?;
|
|
||||||
match bytes {
|
|
||||||
Some(bytes) => bytes.try_into().map_err(LoadableError::Error),
|
|
||||||
None => Err(LoadableError::Missing(id.blobstore_key())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_blobstore_conversions!($handle);
|
|
||||||
impl_blobstore_conversions!($ty);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_loadable_storable!(TreeHandle, Tree);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user