remove ipc codegen from ethcore
This commit is contained in:
parent
6f914d1851
commit
fa019bd03e
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -525,9 +525,6 @@ dependencies = [
|
|||||||
"ethcore-bytes 0.1.0",
|
"ethcore-bytes 0.1.0",
|
||||||
"ethcore-devtools 1.9.0",
|
"ethcore-devtools 1.9.0",
|
||||||
"ethcore-io 1.9.0",
|
"ethcore-io 1.9.0",
|
||||||
"ethcore-ipc 1.9.0",
|
|
||||||
"ethcore-ipc-codegen 1.9.0",
|
|
||||||
"ethcore-ipc-nano 1.9.0",
|
|
||||||
"ethcore-logger 1.9.0",
|
"ethcore-logger 1.9.0",
|
||||||
"ethcore-stratum 1.9.0",
|
"ethcore-stratum 1.9.0",
|
||||||
"ethcore-util 1.9.0",
|
"ethcore-util 1.9.0",
|
||||||
|
@ -5,10 +5,6 @@ license = "GPL-3.0"
|
|||||||
name = "ethcore"
|
name = "ethcore"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
build = "build.rs"
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
"ethcore-ipc-codegen" = { path = "../ipc/codegen" }
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.9"
|
ansi_term = "0.9"
|
||||||
@ -26,8 +22,6 @@ memorydb = { path = "../util/memorydb" }
|
|||||||
patricia_trie = { path = "../util/patricia_trie" }
|
patricia_trie = { path = "../util/patricia_trie" }
|
||||||
ethcore-devtools = { path = "../devtools" }
|
ethcore-devtools = { path = "../devtools" }
|
||||||
ethcore-io = { path = "../util/io" }
|
ethcore-io = { path = "../util/io" }
|
||||||
ethcore-ipc = { path = "../ipc/rpc" }
|
|
||||||
ethcore-ipc-nano = { path = "../ipc/nano" }
|
|
||||||
ethcore-logger = { path = "../logger" }
|
ethcore-logger = { path = "../logger" }
|
||||||
ethcore-stratum = { path = "../stratum" }
|
ethcore-stratum = { path = "../stratum" }
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
extern crate ethcore_ipc_codegen;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
ethcore_ipc_codegen::derive_ipc_cond("src/client/traits.rs", cfg!(feature="ipc")).unwrap();
|
|
||||||
ethcore_ipc_codegen::derive_ipc_cond("src/snapshot/snapshot_service_trait.rs", cfg!(feature="ipc")).unwrap();
|
|
||||||
ethcore_ipc_codegen::derive_ipc_cond("src/client/chain_notify.rs", cfg!(feature="ipc")).unwrap();
|
|
||||||
}
|
|
@ -14,12 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ipc::IpcConfig;
|
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
/// Represents what has to be handled by actor listening to chain events
|
/// Represents what has to be handled by actor listening to chain events
|
||||||
#[ipc]
|
|
||||||
pub trait ChainNotify : Send + Sync {
|
pub trait ChainNotify : Send + Sync {
|
||||||
/// fires when chain has new blocks.
|
/// fires when chain has new blocks.
|
||||||
fn new_blocks(
|
fn new_blocks(
|
||||||
@ -57,5 +55,3 @@ pub trait ChainNotify : Send + Sync {
|
|||||||
// does nothing by default
|
// does nothing by default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpcConfig for ChainNotify { }
|
|
||||||
|
@ -45,21 +45,6 @@ pub use vm::{LastHashes, EnvInfo};
|
|||||||
pub use error::{BlockImportError, TransactionImportError, TransactionImportResult};
|
pub use error::{BlockImportError, TransactionImportError, TransactionImportResult};
|
||||||
pub use verification::VerifierType;
|
pub use verification::VerifierType;
|
||||||
|
|
||||||
/// IPC interfaces
|
mod traits;
|
||||||
#[cfg(feature="ipc")]
|
|
||||||
pub mod remote {
|
|
||||||
pub use super::traits::RemoteClient;
|
|
||||||
pub use super::chain_notify::ChainNotifyClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod traits {
|
|
||||||
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/traits.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod chain_notify {
|
|
||||||
//! Chain notify interface
|
|
||||||
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/chain_notify.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mod chain_notify;
|
||||||
|
@ -27,7 +27,6 @@ use evm::{Factory as EvmFactory, Schedule};
|
|||||||
use executive::Executed;
|
use executive::Executed;
|
||||||
use filter::Filter;
|
use filter::Filter;
|
||||||
use header::{BlockNumber};
|
use header::{BlockNumber};
|
||||||
use ipc::IpcConfig;
|
|
||||||
use log_entry::LocalizedLogEntry;
|
use log_entry::LocalizedLogEntry;
|
||||||
use receipt::LocalizedReceipt;
|
use receipt::LocalizedReceipt;
|
||||||
use trace::LocalizedTrace;
|
use trace::LocalizedTrace;
|
||||||
@ -49,7 +48,6 @@ use types::block_status::BlockStatus;
|
|||||||
use types::mode::Mode;
|
use types::mode::Mode;
|
||||||
use types::pruning_info::PruningInfo;
|
use types::pruning_info::PruningInfo;
|
||||||
|
|
||||||
#[ipc(client_ident="RemoteClient")]
|
|
||||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||||
pub trait BlockChainClient : Sync + Send {
|
pub trait BlockChainClient : Sync + Send {
|
||||||
|
|
||||||
@ -287,8 +285,6 @@ pub trait BlockChainClient : Sync + Send {
|
|||||||
fn eip86_transition(&self) -> u64;
|
fn eip86_transition(&self) -> u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpcConfig for BlockChainClient { }
|
|
||||||
|
|
||||||
/// Extended client interface used for mining
|
/// Extended client interface used for mining
|
||||||
pub trait MiningBlockChainClient: BlockChainClient {
|
pub trait MiningBlockChainClient: BlockChainClient {
|
||||||
/// Returns OpenBlock prepared for closing.
|
/// Returns OpenBlock prepared for closing.
|
||||||
|
@ -29,7 +29,6 @@ use io::*;
|
|||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use client::Error as ClientError;
|
use client::Error as ClientError;
|
||||||
use ipc::binary::{BinaryConvertError, BinaryConvertable};
|
|
||||||
use snapshot::Error as SnapshotError;
|
use snapshot::Error as SnapshotError;
|
||||||
use engines::EngineError;
|
use engines::EngineError;
|
||||||
use ethkey::Error as EthkeyError;
|
use ethkey::Error as EthkeyError;
|
||||||
@ -486,21 +485,3 @@ impl<E> From<Box<E>> for Error where Error: From<E> {
|
|||||||
Error::from(*err)
|
Error::from(*err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binary_fixed_size!(BlockError);
|
|
||||||
binary_fixed_size!(ImportError);
|
|
||||||
binary_fixed_size!(TransactionError);
|
|
||||||
|
|
||||||
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
|
|
||||||
/*#![feature(concat_idents)]
|
|
||||||
macro_rules! assimilate {
|
|
||||||
($name:ident) => (
|
|
||||||
impl From<concat_idents!($name, Error)> for Error {
|
|
||||||
fn from(err: concat_idents!($name, Error)) -> Error {
|
|
||||||
Error:: $name (err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
assimilate!(FromHex);
|
|
||||||
assimilate!(BaseData);*/
|
|
||||||
|
@ -81,7 +81,6 @@ extern crate ethash;
|
|||||||
extern crate ethcore_bloom_journal as bloom_journal;
|
extern crate ethcore_bloom_journal as bloom_journal;
|
||||||
extern crate ethcore_devtools as devtools;
|
extern crate ethcore_devtools as devtools;
|
||||||
extern crate ethcore_io as io;
|
extern crate ethcore_io as io;
|
||||||
extern crate ethcore_ipc_nano as nanoipc;
|
|
||||||
extern crate ethcore_bigint as bigint;
|
extern crate ethcore_bigint as bigint;
|
||||||
extern crate ethcore_bytes as bytes;
|
extern crate ethcore_bytes as bytes;
|
||||||
extern crate ethcore_logger;
|
extern crate ethcore_logger;
|
||||||
@ -139,8 +138,6 @@ extern crate macros;
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
|
||||||
extern crate ethcore_ipc as ipc;
|
|
||||||
#[cfg_attr(test, macro_use)]
|
#[cfg_attr(test, macro_use)]
|
||||||
extern crate evm;
|
extern crate evm;
|
||||||
|
|
||||||
|
@ -30,12 +30,8 @@ use miner::Miner;
|
|||||||
|
|
||||||
use snapshot::{ManifestData, RestorationStatus};
|
use snapshot::{ManifestData, RestorationStatus};
|
||||||
use snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
|
use snapshot::service::{Service as SnapshotService, ServiceParams as SnapServiceParams};
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use ansi_term::Colour;
|
use ansi_term::Colour;
|
||||||
|
|
||||||
#[cfg(feature="ipc")]
|
|
||||||
use nanoipc;
|
|
||||||
|
|
||||||
/// Message type for external and internal events
|
/// Message type for external and internal events
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum ClientIoMessage {
|
pub enum ClientIoMessage {
|
||||||
@ -73,7 +69,7 @@ impl ClientService {
|
|||||||
spec: &Spec,
|
spec: &Spec,
|
||||||
client_path: &Path,
|
client_path: &Path,
|
||||||
snapshot_path: &Path,
|
snapshot_path: &Path,
|
||||||
ipc_path: &Path,
|
_ipc_path: &Path,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
) -> Result<ClientService, Error>
|
) -> Result<ClientService, Error>
|
||||||
{
|
{
|
||||||
@ -121,7 +117,6 @@ impl ClientService {
|
|||||||
spec.engine.register_client(Arc::downgrade(&client) as _);
|
spec.engine.register_client(Arc::downgrade(&client) as _);
|
||||||
|
|
||||||
let stop_guard = ::devtools::StopGuard::new();
|
let stop_guard = ::devtools::StopGuard::new();
|
||||||
run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share());
|
|
||||||
|
|
||||||
Ok(ClientService {
|
Ok(ClientService {
|
||||||
io_service: Arc::new(io_service),
|
io_service: Arc::new(io_service),
|
||||||
@ -229,38 +224,6 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature="ipc")]
|
|
||||||
fn run_ipc(base_path: &Path, client: Arc<Client>, snapshot_service: Arc<SnapshotService>, stop: Arc<AtomicBool>) {
|
|
||||||
let mut path = base_path.to_owned();
|
|
||||||
path.push("parity-chain.ipc");
|
|
||||||
let socket_addr = format!("ipc://{}", path.to_string_lossy());
|
|
||||||
let s = stop.clone();
|
|
||||||
::std::thread::spawn(move || {
|
|
||||||
let mut worker = nanoipc::Worker::new(&(client as Arc<BlockChainClient>));
|
|
||||||
worker.add_reqrep(&socket_addr).expect("Ipc expected to initialize with no issues");
|
|
||||||
|
|
||||||
while !s.load(::std::sync::atomic::Ordering::Relaxed) {
|
|
||||||
worker.poll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut path = base_path.to_owned();
|
|
||||||
path.push("parity-snapshot.ipc");
|
|
||||||
let socket_addr = format!("ipc://{}", path.to_string_lossy());
|
|
||||||
::std::thread::spawn(move || {
|
|
||||||
let mut worker = nanoipc::Worker::new(&(snapshot_service as Arc<::snapshot::SnapshotService>));
|
|
||||||
worker.add_reqrep(&socket_addr).expect("Ipc expected to initialize with no issues");
|
|
||||||
|
|
||||||
while !stop.load(::std::sync::atomic::Ordering::Relaxed) {
|
|
||||||
worker.poll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature="ipc"))]
|
|
||||||
fn run_ipc(_base_path: &Path, _client: Arc<Client>, _snapshot_service: Arc<SnapshotService>, _stop: Arc<AtomicBool>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -72,16 +72,7 @@ mod watcher;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
/// IPC interfaces
|
mod traits;
|
||||||
#[cfg(feature="ipc")]
|
|
||||||
pub mod remote {
|
|
||||||
pub use super::traits::RemoteSnapshotService;
|
|
||||||
}
|
|
||||||
|
|
||||||
mod traits {
|
|
||||||
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/snapshot_service_trait.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to have chunks be around 4MB (before compression)
|
// Try to have chunks be around 4MB (before compression)
|
||||||
const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
|
const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024;
|
||||||
|
@ -17,13 +17,11 @@
|
|||||||
use super::{ManifestData, RestorationStatus};
|
use super::{ManifestData, RestorationStatus};
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use ipc::IpcConfig;
|
|
||||||
|
|
||||||
/// The interface for a snapshot network service.
|
/// The interface for a snapshot network service.
|
||||||
/// This handles:
|
/// This handles:
|
||||||
/// - restoration of snapshots to temporary databases.
|
/// - restoration of snapshots to temporary databases.
|
||||||
/// - responding to queries for snapshot manifests and chunks
|
/// - responding to queries for snapshot manifests and chunks
|
||||||
#[ipc(client_ident="RemoteSnapshotService")]
|
|
||||||
pub trait SnapshotService : Sync + Send {
|
pub trait SnapshotService : Sync + Send {
|
||||||
/// Query the most recent manifest data.
|
/// Query the most recent manifest data.
|
||||||
fn manifest(&self) -> Option<ManifestData>;
|
fn manifest(&self) -> Option<ManifestData>;
|
||||||
@ -54,5 +52,3 @@ pub trait SnapshotService : Sync + Send {
|
|||||||
/// no-op if currently restoring.
|
/// no-op if currently restoring.
|
||||||
fn restore_block_chunk(&self, hash: H256, chunk: Bytes);
|
fn restore_block_chunk(&self, hash: H256, chunk: Bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IpcConfig for SnapshotService { }
|
|
@ -18,7 +18,3 @@ pub mod helpers;
|
|||||||
mod client;
|
mod client;
|
||||||
mod evm;
|
mod evm;
|
||||||
mod trace;
|
mod trace;
|
||||||
|
|
||||||
#[cfg(feature="ipc")]
|
|
||||||
mod rpc;
|
|
||||||
|
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Client RPC tests
|
|
||||||
|
|
||||||
use nanoipc;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{Ordering, AtomicBool};
|
|
||||||
use client::{Client, BlockChainClient, ClientConfig, BlockId};
|
|
||||||
use client::remote::RemoteClient;
|
|
||||||
use tests::helpers::*;
|
|
||||||
use devtools::*;
|
|
||||||
use miner::Miner;
|
|
||||||
use crossbeam;
|
|
||||||
use io::IoChannel;
|
|
||||||
use util::kvdb::DatabaseConfig;
|
|
||||||
|
|
||||||
pub fn run_test_worker(scope: &crossbeam::Scope, stop: Arc<AtomicBool>, socket_path: &str) {
|
|
||||||
let socket_path = socket_path.to_owned();
|
|
||||||
scope.spawn(move || {
|
|
||||||
let temp = RandomTempPath::create_dir();
|
|
||||||
let spec = get_test_spec();
|
|
||||||
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
|
||||||
|
|
||||||
let client = Client::new(
|
|
||||||
ClientConfig::default(),
|
|
||||||
&spec,
|
|
||||||
temp.as_path(),
|
|
||||||
Arc::new(Miner::with_spec(&spec)),
|
|
||||||
IoChannel::disconnected(),
|
|
||||||
&db_config
|
|
||||||
).unwrap();
|
|
||||||
let mut worker = nanoipc::Worker::new(&(client as Arc<BlockChainClient>));
|
|
||||||
worker.add_reqrep(&socket_path).unwrap();
|
|
||||||
while !stop.load(Ordering::Relaxed) {
|
|
||||||
worker.poll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_handshake() {
|
|
||||||
crossbeam::scope(|scope| {
|
|
||||||
let stop_guard = StopGuard::new();
|
|
||||||
let socket_path = "ipc:///tmp/parity-client-rpc-10.ipc";
|
|
||||||
run_test_worker(scope, stop_guard.share(), socket_path);
|
|
||||||
let remote_client = nanoipc::generic_client::<RemoteClient<_>>(socket_path).unwrap();
|
|
||||||
|
|
||||||
assert!(remote_client.handshake().is_ok());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_query_block() {
|
|
||||||
crossbeam::scope(|scope| {
|
|
||||||
let stop_guard = StopGuard::new();
|
|
||||||
let socket_path = "ipc:///tmp/parity-client-rpc-20.ipc";
|
|
||||||
run_test_worker(scope, stop_guard.share(), socket_path);
|
|
||||||
let remote_client = nanoipc::generic_client::<RemoteClient<_>>(socket_path).unwrap();
|
|
||||||
|
|
||||||
let non_existant_block = remote_client.block_header(BlockId::Number(999));
|
|
||||||
|
|
||||||
assert!(non_existant_block.is_none());
|
|
||||||
})
|
|
||||||
}
|
|
@ -51,7 +51,6 @@ impl<T> Diff<T> where T: Eq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
|
||||||
/// Account diff.
|
/// Account diff.
|
||||||
pub struct AccountDiff {
|
pub struct AccountDiff {
|
||||||
/// Change in balance, allowed to be `Diff::Same`.
|
/// Change in balance, allowed to be `Diff::Same`.
|
||||||
@ -65,7 +64,6 @@ pub struct AccountDiff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
#[cfg_attr(feature = "ipc", binary)]
|
|
||||||
/// Change in existance type.
|
/// Change in existance type.
|
||||||
// TODO: include other types of change.
|
// TODO: include other types of change.
|
||||||
pub enum Existance {
|
pub enum Existance {
|
||||||
|
Loading…
Reference in New Issue
Block a user