Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[x/programs/rust] Use clippy::pedantic in the SDK #395

Merged
merged 5 commits into from
Aug 31, 2023
Merged

Conversation

richardpringle
Copy link
Contributor

Clippy::pendantic saves you from yourself. I recommend this for any open-source Rust (then ignore rules where it's overkill).

// always deallocate the full capacity, initialize vs uninitialized memory is irrelevant here
let data = Vec::from_raw_parts(ptr, capacity, capacity);
std::mem::drop(data);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clippy didn't like the usage of #[no_mangle] here. It doesn't make sense to have the #[no_mangle] attribute if the function isn't being exported with extern "C" fn // ....

So instead of exposing a function that isn't being called from the wasm-host, I figured it's probably better to delete these. Let me know if you (the reviewer) thinks otherwise.

Copy link
Contributor

@samliok samliok Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need #[no_mange] when dealing with wazero and the rust compiler. Otherwise, the compiler can you change the function signature which causes an error in the host.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should also have extern "C" in that case (at least that's what clippy says)

@richardpringle
Copy link
Contributor Author

If @hexfusion or @samliok have any Rust work-in-progress, that should definitely be merged first. It would be hard to redo this stuff.

Please pay close attention to the # Errors sections that were missing on functions. The docs are my best guess as describing error scenarios and could probably use better language. Please make suggestions!

Copy link
Contributor

@samliok samliok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely should wait on this PR until #388 . I've changed a lot of the stuff edited here. The Error changes are helpful tho.

@richardpringle richardpringle marked this pull request as draft August 23, 2023 20:07
@richardpringle richardpringle marked this pull request as ready for review August 30, 2023 15:36
@@ -83,7 +87,7 @@ pub fn host_program_invoke(call_ctx: &Context, method_name: &str, args: &[u8]) -
/// Allocate memory into the module's linear memory
/// and return the offset to the start of the block.
#[no_mangle]
pub fn alloc(len: usize) -> *mut u8 {
pub extern "C" fn alloc(len: usize) -> *mut u8 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rust does not have a stable ABI, and while it's unlikely to change for function signatures, there are no guarantees. What that means is external calls could break when calling the same "binary" (WASM in this case) compiled with different versions of Rust. extern "C" uses the C ABI, which is stable.

@@ -1,40 +1,48 @@
use crate::errors::StorageError;
use crate::host::host_program_invoke;
use crate::host::program_invoke;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No stutters like host::host_*

use crate::host::{get_bytes, get_bytes_len, store_bytes};
use crate::types::Argument;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_bare::{from_slice, to_vec};
use std::str;

pub enum StoreResult<'a> {
Ok(&'a Context),
#[allow(clippy::module_name_repetitions)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another stutter, but I think it's fine to ignore here since causing a collision with std::result::Result would be a pain.

Ok(&'a Context),
#[allow(clippy::module_name_repetitions)]
pub enum StoreResult {
Ok(Context),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this since the Context type is Copy... same reasoning as explained above.

pub fn store_value<T>(self, key: &str, value: &T) -> Self
where
T: Serialize + ?Sized,
{
match self {
Self::Ok(ctx) => ctx.store_value(key, value),
err => err,
err @ Self::Err(_) => err,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now if we are to add new variants to StoreResult, we have to handle the behaviour explicitly.


/// Returns the value of the field `name` from the host.
/// # Errors
/// Returns a `StorageError` if the field does not exist or if the bytes are invalid.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samliok, are these comments accurate?


/// Returns the value of the field `key` from the map `map_name` from the host.
/// # Errors
/// Returns a `StorageError` if the field does not exist or if the bytes are invalid.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samliok, are these comments accurate?

@@ -102,7 +120,7 @@ impl From<i64> for Context {
}
}

fn store_key_value<T>(ctx: &Context, key_bytes: Vec<u8>, value: &T) -> Result<(), StorageError>
fn store_key_value<T>(ctx: Context, key_bytes: &[u8], value: &T) -> Result<(), StorageError>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was an interesting one... passing in a Vec<u8> here assures that the memory is deallocated after this function exits, which might be desired. However, I did find one place where we were calling to_vec to pass in a value to store_key_value, so taking in a slice requires one less allocation.

I think this is better, but I'm open to an argument for the contrary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passed in a Vec since we don't need the memory after, but if its faster I'm all for it.

Comment on lines +163 to +164
bytes_len.try_into().unwrap(),
bytes_len.try_into().unwrap(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know there's a check above assuring that the cast will succeed, but generally it's better to avoid using as casts with numbers unless you're doing something that's guaranteed to succeed (like usize as u64).

I think there are some other improvements that can be made to this function (like calling into_boxed_slice so that you can't expand the Vec) and possible changing the return type for get_bytes_len, but that's for another PR.

Err(StorageError),
}

impl StoreResult<'_> {
impl StoreResult {
#[must_use]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why must_use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷 clippy --fix.

Means you have to use the return value. I think it makes sense.

@@ -102,7 +120,7 @@ impl From<i64> for Context {
}
}

fn store_key_value<T>(ctx: &Context, key_bytes: Vec<u8>, value: &T) -> Result<(), StorageError>
fn store_key_value<T>(ctx: Context, key_bytes: &[u8], value: &T) -> Result<(), StorageError>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passed in a Vec since we don't need the memory after, but if its faster I'm all for it.

where
T: DeserializeOwned,
{
let bytes = get_field_as_bytes(ctx, name.as_bytes())?;
from_slice(&bytes).map_err(|_| StorageError::InvalidBytes)
}

/// Gets the correct key to in the host storage for a [map_name] and [key] within that map
/// Gets the correct key to in the host storage for a [`map_name`] and [key] within that map
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why `` and []?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clippy --fix... but good call out, these docs are actually not formatted properly.

@richardpringle richardpringle requested a review from samliok August 30, 2023 20:13
@richardpringle richardpringle requested a review from samliok August 30, 2023 20:13
richardpringle and others added 2 commits August 30, 2023 17:08
Co-authored-by: Sam Liokumovich <[email protected]>
Signed-off-by: Richard Pringle <[email protected]>
Co-authored-by: Sam Liokumovich <[email protected]>
Signed-off-by: Richard Pringle <[email protected]>
@patrick-ogrady patrick-ogrady merged commit 369192d into main Aug 31, 2023
@hexfusion hexfusion deleted the clippy branch September 4, 2023 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants