How to print public fields of object/type in rust?

I have an object and I would like to know what fields are possibly available for that object, is there a way to do that?

In my specific case,
the type of my object is jsonrpc_client_core::Error,
and I can use println!("error: {:#?}) and see the output:

    JsonRpcError(
        Error {
            code: ServerError(
                -32027,
            ),
            message: "Failed to connect to network wlan0 for peach-probe-test-ssid",
            data: None,
        },
    ),
    State {
        next_error: None,
        backtrace: InternalBacktrace {
            backtrace: None,
        },
    },
)

However, when I try to access a field via:
e.code
I get the compilation error:
error[E0609]: no field `code` on type `jsonrpc_client_core::Error

How can I see what fields I am actually able to access on an object? I would prefer a way to do it programmatically instead of by looking in documentation.

In the end my goal is to get the value of the code field so I can do something with it.

Thanks for any help!

There isn't a way to programmatically get the fields of a type in general. You'll have to look at the documentation. Note: you can build a local copy of the documentation for your crate, which will also include the docs for all of your dependencies then look in there.

In this case, the Error type that you want is jsonrpc_core::types::error::Error, which is different from jsonrpc_client_core::Error.

1 Like

thank you @RustyYato, and for the tip about local documentation - that sounds great for working offline.

so in my case I guess I have an object of type jsonrpc_client_core::Error, which itself doesn't have a code field.

what I need then is to somehow get the jsonrpc_core::types::error::Error inside of it, so that I can then access the code field

Yes, one way to do that is to call jsonrpc_client_core::Error::kind, if that's in the jsonrpc_client_core::ErrorKind::JsonRpcError variant, which holds a jsonrpc_core::types::error::Error.

1 Like

ok I still haven't quite figured out how to get the code out, but I'm on the path, thanks!

1 Like

alas I am still a bit stuck.

This is my current code:

   match e.kind() {
                            // this is the expected error, all other errors are unexpected
                            jsonrpc_client_core::ErrorKind::JsonRpcError(err) => {
                                println!("code: {:?}", err.code);
                                match err.code {
                                    jsonrpc_core::types::error::ErrorCode::ServerError(code_number) => {
                                        println!("++ matching code number: {:?}", code_number);
                                        result.successes.push(endpoint_name.to_string());
                                    }
                                    _ => {
                                        eprintln!("++ {} endpoint is offline", endpoint_name);
                                        eprintln!("Returned unexpected JsonRpcCore error: {:#?}\n", e);
                                        result.failures.push(endpoint_name.to_string());
                                    }
                                }
                            }
                            _ => {
                                eprintln!("++ {} endpoint is offline", endpoint_name);
                                eprintln!("Returned unexpected JsonRpcCore error: {:#?}\n", e);
                                result.failures.push(endpoint_name.to_string());
                            }
                        }

and I get this error:

79 | ...                       jsonrpc_core::types::error::ErrorCode::ServerError(code_number) => {
   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `jsonrpc_core::types::error::ErrorCode`, found enum `ErrorCode`

feel like I still can't read the type documentation well enough to understand why the types do not match

jsonrpc_core::types::error::ErrorCode::ServerError

I could also post this as a separate topic if this has strayed too far from the original question

That's strange, what versions of each library are you using? I'm not able to reproduce that error message when using

[dependencies]
jsonrpc-client-core = "0.5"
jsonrpc-core = "8"

With this snippet

fn foo(error: jsonrpc_client_core::Error) {
    if let jsonrpc_client_core::ErrorKind::JsonRpcError(error) = error.kind() {
        if let jsonrpc_core::types::error::ErrorCode::ServerError(code) = error.code {

        }
    }
}

@RustyYato
Aw interesting,
when I run your snippet with the library versions you have listed for me, it works.

But I was using:

[dependencies]
jsonrpc-client-core = "0.5"
jsonrpc-core = "14.2"

which when I run your snippet gives me the same error I was getting before

expected enum `jsonrpc_core::types::error::ErrorCode`, found enum `ErrorCode`

I also see this same error for the snippet when I upgrade the jsonrpc-core to the latest version, 16.0.0, listed here https://crates.io/crates/jsonrpc-core

jsonrpc-client-core requires jsonrpc-core of version 8.x. If you use the type from more recent version along with the one required by jsonrpc-client-core, they are two entirely different types, just having the same name.

3 Likes

@Cerberuser thank you!

I'm wondering, is there a way to easily know beforehand when these types of library conflicts could happen?

To simplify for discussion.
Lets say I am using library A and library BversionY, and library A itself depends on library BversionZ.

Can I know beforehand when this will create conflicts?
As clearly sometimes its ok to use a library which depends on a different version of a library which I am also using.

It's rather simple, in fact:

  • By default (i.e. if version is not explicitly pinned), Cargo will use newest semver-compatible version, i.e. newest version with the same first non-zero number with the required one.
    • That means: if the crate requires some_crate = "0.1.2", Cargo will use version "0.1.x" with some x >= 2; if the crate requires some_crate = "1.2.3", Cargo will use "1.x.y" with either x >= 2 && y >= 3 or x >= 3.
  • If there are several semver-compatible requrements, Cargo will pull only one version, according to all these requirements.
    • That means, e.g.: if your crate requires some_crate = "0.1.2", and your dependency requires some_crate = "0.1.3", Cargo will use "0.1.x" with x >= 3, since this is compatible with both requirements.
  • If there are several semver-incompatible requirements, Cargo will pull different versions for each requirement (or group of requirements), which are completely independent from the compiler's perspective. So they won't be compatible, unless the crate in question uses semver trick.
    • That means: if you require some_crate = "2.0.0", and one of your dependencies requires some_crate = "1.0.0", Cargo will try to use both "1.x.y" and "2.x.y", and here's how the conflict appears.

@cerbeuser this is helpful a breakdown and makes sense.

I have an additional question for the third case you described:
if my crate requires some_create = "2.0.0" and one my dependencies requires some_create = "1.0.0" , it seems this will not always create conflicts. The libraries are incompatible via semver, but I guess its only when a library like jsonrpc-client-core exposes a type from its dependency, that this creates a possible conflict with the version I am using.

My question is:

A: is it considered a bad practice to require some_crate="2.0.0" and require another_crate which depends on some_create="1.0.0" (incompatible by semver)

or

B: its not bad practice to do this, but one just needs to be aware of the typing, and that the types of some_create referenced by another_create may not match the types of some_crate that you import from some_crate directly.

And if B is true, then what are some strategies for realizing when you might be using incompatible types. Would be nice if the compiler could tell me somehow that I am comparing two types from two different versions of the same crate...

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.