How do I 'force' structs to implement the same traits? - rust

I have the following:
pub struct OpBStruct {
title: String,
output_vale: i32,
}
impl OpBStruct {
pub fn new_OpB(in_title: String, in_output_vale: i32) -> OpBStruct {
OpBStruct {
title: in_title,
output_vale: in_output_vale,
}
}
}
pub struct OpCStruct {
title: String,
another_value: String,
output_vale: i32,
}
impl OpCStruct {
pub fn new_OpC(in_title: String, in_another_value: String, in_output_vale: i32) -> OpCStruct {
OpCStruct {
title: in_title,
another_value: in_another_value,
output_vale: in_output_vale,
}
}
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
pub enum Op {
OpB(OpBStruct),
OpC(OpCStruct),
}
pub struct A {
name: String,
operator: Op,
}
impl A {
pub fn new_A(in_name: String, in_operator: Op) -> A {
A {
name: in_name,
operator: in_operator,
}
}
}
The exact structure of OpBStruct and OpCStruct are arbitrary and could be anything.
How do I make sure OpBStruct and OpCStruct implement a certain trait?
trait OpTrait {
pub fn get_op_output(&self) -> i32;
}
I thought about making a sort of constructor function that checked for an OpTrait trait requirement and it would be the only way one could create an Op instance, but each operator requires different initialization parameters and there's no way to specify a variable number of inputs for a function in Rust.
Something like this doesn't work because there's no way to input the initialization parameters:
pub fn new_op<T: OpTrait>(operator: T) {
// --snip--
}
I thought about somehow using the new_A method implemented on A to check if the in_operator has implemented the trait, but I'm not sure how to do that either.
What is the correct pattern for this? If there is none, I can just implement the trait for each Op with no sort of interface around it.

I would also recommend writing a test, however you can write a function which is generic over a type but takes no arguments:
struct X {}
trait Y {
fn yo();
}
fn is_y<T: Y>(){}
Then you can add the following line to do the check
is_y::<X>();
which will compile only if X implements Y.

Using a unit test would be a fairly straightforward way to enforce that you want a given trait on a struct. You can do it via implicit test code, but a small utility function to do so can express the intent a little more clearly.
If you have indicated trait inputs on functions in the rest of the code, it might come out fairly naturally without the unit test. The test has the advantage of letting you have an opportunity to explicitly check some invariant of the trait implementation too.
struct A {
val: u8,
}
struct B {
val: u32,
}
trait ExpandToU64 {
fn to_u64(&self) -> u64;
}
impl ExpandToU64 for A {
fn to_u64(&self) -> u64
{
self.val as u64
}
}
fn trait_tester<E>(a: E)
where E: ExpandToU64
{
// the utility function doesn't have to even use the trait...
// but you probably want to exercise the logic a bit
//let v = a.to_u64();
let v = 24u64;
println!("{:?}", v);
}
#[test]
fn test_needs_trait_ExpandToU64() {
let a = A { val:1 };
trait_tester(a);
let b = B { val:2 };
trait_tester(b);
// This fails with a compile error
// "the trait `ExpandToU64` is not implemented for `B`"
}

Related

How do i resolve type annotations needed cannot infer type for type parameter `T` ? What type annotation is needed to compile this code?

The blockchain struct definition, It defines a type and i use the type
pub struct Blockchain<T = SledDb> {
pub storage: T,
pub chain: Vec<Block>,
pub tip: Arc<RwLock<String>>,
pub height: AtomicUsize,
pub mempool: Mempool,
pub wallet: Wallet,
pub accounts: Account,
pub stakes: Stake,
pub validators: Validator,
}
This code is checking if stake is valid.The code for mining a block, the error is immited by is_staking_valid function. I don't know what type its asking for since i already specified one.
impl<T: Storage> Blockchain<T> {
pub fn is_staking_valid(
balance: u64,
difficulty: u32,
timestamp: i64,
prev_hash: &String,
address: &String,
) -> bool {
let base = BigUint::new(vec![2]);
let balance_diff_mul = base.pow(256) * balance as u32;
let balance_diff = balance_diff_mul / difficulty as u64;
let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
let sha256_hash = digest(data_str);
let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
staking_hash <= balance_diff
}
pub fn mine_block(&mut self, data: &str) -> Option<Block> {
if self.mempool.transactions.len() < 2 {
info!("Skipping mining because no transaction in mempool");
return None;
}
let balance = self
.stakes
.get_balance(&self.wallet.get_public_key())
.clone();
let difficulty = self.get_difficulty();
info!("New block mining initialized with difficulty {}", difficulty);
let timestamp = Utc::now().timestamp();
let prev_hash = self.chain.last().unwrap().hash.clone();
let address = self.wallet.get_public_key();
if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
let block = self.create_block(&data, timestamp);
self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
Some(block)
} else {
None
}
}
}
Please find the compiler error below
error[E0282]: type annotations needed
--> src/blocks/chain.rs:173:12
|
173 | if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`
For more information about this error, try `rustc --explain E0282`.
Minimized example:
pub struct Blockchain<T> {
pub storage: T,
}
impl<T> Blockchain<T> {
pub fn is_staking_valid() {
todo!()
}
pub fn mine_block(&mut self) {
Blockchain::is_staking_valid();
}
}
Playground
The reason for this error is that Blockchain::<T1>::is_staking_valid and Blockchain::<T2>::is_staking_valid are, as well as compiler is concerned, two separate, entirely unrelated functions. Yes, they have the same code, and yes, they will be deduplicated by the optimizer, but this doesn't have to be the case - e.g., if this function used some associated item available on T:
trait Stakable {
const IS_VALID: bool;
}
impl Stakable for () {
const IS_VALID: bool = false;
}
impl Stakable for i32 {
const IS_VALID: bool = true;
}
struct Blockchain<T> {
pub _storage: T,
}
impl<T: Stakable> Blockchain<T> {
fn validate() {
if !T::IS_VALID {
panic!("Type is not valid");
}
}
}
fn main() {
// This panics - we catch this panic and show that it has indeed happened
std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
// This executes successfully
Blockchain::<i32>::validate();
}
Playground
Because of the possible ambiguity, compiler refuses to choose by itself and forces you to make the selection explicitly.
So, you have several possible ways to go:
Make is_staking_valid a free function, instead of associated function of Blockchain. In this case, it won't be able to depend on Blockchain's type parameter, therefore the call will be unambiguous.
Call Self::is_staking_valid instead of Blockchain::is_staking_valid. In this case, Self will be replaced with Blockchain::<T>, with T taken from the currently executed method; this will, again, resolve ambiguity.
Make is_staking_valid a method on Blockchain, i.e. make it receive &self, and call it via self.is_staking_valid().
Not recommended, but still possible, - make is_staking_valid an associated function on Blockchain<T> for some specific T, e.g.:
pub struct Blockchain<T> {
pub storage: T,
}
impl Blockchain<()> {
// Note - no free type parameters here!
pub fn is_staking_valid() {
todo!()
}
}
impl<T> Blockchain<T> {
pub fn mine_block(&mut self) {
// Here, `Blockchain` is `Blockchain::<()>` - the method is set
Blockchain::is_staking_valid();
}
}

Shorthand way of generating owned strings

Given the following struct (in practice, its bigger than this):
#[derive(Deserialize, Debug)]
struct Parameter {
name: String,
value: String,
}
If I want to create an instance of this (for tests, etc.):
Parameter {
name: "name".to_string(),
value: "value".to_string()
}
I have to call to_string on the end of all my values. This is a bit annoying. Is there a shorthand way of creating an owned string?
You could always shorten it with a macro:
macro_rules! s {
($s:expr) => { $s.to_string() }
}
#[derive(Debug)]
struct Parameter {
name: String,
value: String,
}
fn main() {
println!("{:?}", Parameter { name: s!("foo"), value: s!("bar"), });
}
Playground
The macro by Jmb works fine, but I prefer to use plain functions where possible. (I also prefer post-fix operations over prefix+postfix ones)
So this is the variant I have used:
pub trait ToStringExt : ToString {
/// Simply an alias for `.to_string()`.
fn s(&self) -> String {
self.to_string()
}
}
impl<T> ToStringExt for T where T: ToString {}
And then to use it:
use to_string_ext::ToStringExt;
fn main() {
let my_str: String = "some string".s();
}
If the only case where you want this shorthand is converting a &str into a String, then this is a narrower alternative: (which I prefer nowadays)
pub trait ToOwnedExt where Self : ToOwned {
/// Simply an alias for `.to_owned()`.
fn o(&self) -> <Self as ToOwned>::Owned {
self.to_owned()
}
}
impl<T: ?Sized> ToOwnedExt for T where T: ToOwned {}
And then to use it:
use to_owned_ext::ToOwnedExt;
fn main() {
let my_str: String = "some string".o();
}

Extending On An SO Answered Question About Strategy Pattern Implementation

As answered by the ever so helpful and ubiquitous Shepmaster, could someone help me with a syntax hurdle I'm encountering?
In the previous answer, Strategy::execute() and Context::do_things() returns ().
How does one implement if a generic type is returned? Or am I missing some fundamental perspective in Rust?
I tried the following code but am currently stuck at:
struct Context<S> {
strategy: S,
}
impl<S> Context<S>
where
S: Strategy,
{
fn do_things(&self) -> T {
println!("Common preamble");
self.strategy.execute()
}
}
trait Strategy<T> {
fn execute(&self) -> T;
}
struct ConcreteStrategyA;
impl Strategy<AStruct> for ConcreteStrategyA {
fn execute(&self) -> AStruct {
println!("ConcreteStrategyA");
AStruct::default()
}
}
struct AStruct {
id: u32,
}
impl Default for AStruct {
...
}
struct ConcreteStrategyB;
impl Strategy<BStruct> for ConcreteStrategyB {
fn execute(&self) -> BStruct {
println!("ConcreteStrategyB");
BStruct::default()
}
}
struct BStruct {
id: u32,
}
impl Default for BStruct {
...
}
I have no idea where to put T for Context::do_things() -> T.
I looked around but some other samples return () as well.
Online tinkering
Thanks for reading.
Depending on what you're trying to do, it might be better to use an associated type instead of a generic. When choosing between associated types and generic parameters, you should use a generic if the caller can choose the type to use. You should use an associated type if the implementation determines the type.
Although there are exceptions (e.g. Into::into), most of the time if a type appears only in the return of a method, then this is a good indication that it should probably be an associated type. OTOH if a type is used for a parameter, then there is a fair chance that it should be a generic.
In your case, using an associated type would look like this:
struct Context<S> {
strategy: S,
}
impl<S> Context<S>
where
S: Strategy,
{
fn do_things(&self) -> S::Output {
println!("Common preamble");
self.strategy.execute()
}
}
trait Strategy {
type Output;
fn execute(&self) -> Self::Output;
}
struct ConcreteStrategyA;
impl Strategy for ConcreteStrategyA {
type Output = AStruct;
fn execute(&self) -> AStruct {
println!("ConcreteStrategyA");
AStruct::default()
}
}
#[derive (Default)]
struct AStruct {
id: u32,
}
struct ConcreteStrategyB;
impl Strategy for ConcreteStrategyB {
type Output = BStruct;
fn execute(&self) -> BStruct {
println!("ConcreteStrategyB");
BStruct::default()
}
}
#[derive (Default)]
struct BStruct {
id: u32,
}
Playground
I think using Strategy<T> more often is the key:
impl<S, T> Context<S, T>
where
S: Strategy<T>,
{
fn do_things(&self) -> T {
println!("Common preamble");
self.strategy.execute()
}
}
See here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a3a14895e22ca57f5f96c855b7046257

How to use traits implemented for some of the types embedded in an enum's variants?

I have an enum with around 20 variants. As traits cannot be implemented for enum's variants (see Can traits be used on enum types? and How do I implement a trait for an enum and its respective variants?) I have implemented my trait for some of the types embedded in the variants.
Given a variable typed as the enum, what is the idiomatic/best way to access the trait? As I need to use this in different places, I tried to move the code in a function and my following attempt returns a Option<Box<&dyn Trait>>.
pub struct X { pub name: String, pub weight: u32 }
pub struct Y { pub name: String }
pub struct Z {}
pub enum Node {
X(X),
Y(Y),
Z(Z),
}
pub trait Weighted {
fn weight(&self) -> u32;
}
impl Weighted for X {
fn weight(&self) -> u32 { return self.weight; }
}
impl Weighted for Z {
fn weight(&self) -> u32 { return 3; }
}
pub fn as_weighted_node(node: &Node) -> Option<Box<&dyn Weighted>> {
match node {
Node::X(x) => Some(Box::new(x)),
Node::Z(z) => Some(Box::new(z)),
_ => None
}
}
let node: Node = Node::X(X { name: "x1".to_string(), weight: 1 });
println!("{}", as_weighted_node(&node).unwrap().weight());
It seems Box is not needed and as_weighted_node can be written as:
pub fn as_weighted_node(node: &Node) -> Option<&dyn Weighted> {
match node {
Node::X(x) => Some(x),
Node::Z(z) => Some(z),
_ => None
}
}
I am still not sure this is the best way to handle this issue though.

Return object implementing multiple traits - decorator pattern

I am currently implementing decorator pattern in Rust.
In Scala we could implement method chaining via traits like:
new Scanner
with Whitespaces
with Keywords
I want to do the same in Rust. So, different traits for scanner:
pub struct Lexer();
pub trait Scan {
fn scan(&self, start: &String) -> DomainTags;
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Scan> Scan for Keywords<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Scan> Scan for Whitespaces<T> {
fn scan(&self, start: &String) -> DomainTags {
...
}
}
But since I want to build my lexers with method like:
pub fn build() -> ??? {
let lex = Lexer();
let lex = Keyword {
decorated: Whitespaces {
decorated: lex
}
};
lex
}
I don't know if it is possible to statically deduce the return type to something like decltype(lex). What is the common approach, towards implementing the method? What could be improved?
To clarify: I want to return decltype(lex), because I may also have multiple traits for single Lexer, like:
pub trait Load {
fn load<T : Load>(&self, keywords: &String);
}
impl Load for Lexer {
fn load<Lexer>(&self, keyword : &String) {
...
}
}
And I hope to return a decorated object with implementation of Load trait as well. Both method load and scan should be available.
A function can only return a single type of value, so the type returned by your function can't depend on runtime conditions. However that type may be a boxed trait, in which case the type of the value stored in the box may change provided it implements the appropriate trait (or traits).
From the example code you've provided, I think that Lexer should be a trait like trait Lexer: Scan + Load {} (or maybe the Scan and Load traits don't need to exist at all and the scan and load methods can be defined directly in Lexer). Then your build function should just return a boxed Lexer:
pub trait Lexer {
fn scan (&self, start: &String) -> DomainTags;
fn load (&self, keyword : &String);
}
pub struct Keywords<T> {
decorated: T
}
impl<T: Lexer> Lexer for Keywords<T> {
…
}
pub struct Whitespaces<T> {
decorated: T
}
impl<T: Lexer> Lexer for Whitespaces<T> {
…
}
pub fn build (cond: bool) -> Box<dyn Lexer> {
if cond {
Box::new (Whitespaces { … })
} else {
Box::new (Keywords { … })
}
}

Resources