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

add fn to_vec for easily printing config values in any simple format #66

Open
JonasJebing opened this issue Jun 24, 2022 · 1 comment
Open

Comments

@JonasJebing
Copy link

JonasJebing commented Jun 24, 2022

💡 Feature description

Personally I would like to be able to easily print out my config in a bash format.
Then I could copy one of the config's env vars from my app's output, change the env var and restart my binary.
Others may want to output their config's env vars in a YAML-like syntax and change them in their kubernetes config.

To provide those use cases with a simple and straight-forward solution, I propose to add the following function to envy:

pub fn to_vec<T: Serialize>(value: &T) -> Result<Vec<(String, String)>> { ... }

💻 Basic example

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug, Default)]
struct Config {
    foo: u16,
    bar: String,
}

for (key, value) in envy::to_vec(&Config::default())? {
    println!("{key}={value:?}");
}
// stdout:
// FOO="0"
// BAR="" 

Alternatives

Use std::fmt::Debug instead

This has the following downsides:

  • Fields aren't SCREAMING_SNAKE_CASE and it's not feasible to output a specific format with Debug.
  • If you have a password field or other secret, you can no longer use derive(Debug).
    With serde you could use #[serde(skip_serializing)].

Write a custom Serializer or fn to_custom_format for every format instead

I think for simple formats writing a Serializer is more complicated than a function using to_vec.

Add a fn to_iter instead

pub fn to_iter<T: Serialize>(value: &T) -> impl Iterator<Item = Result<(String, String)>> + '_ { ... }

I really like this solution, because it is very flexible.
At the least this alternative should be a candidate to add in the future as well.

Implementing this function without using a std::vec::IntoIter is a bit awkward because the Serialize trait does not seem like it's designed for this kind of step-wise serialization to an Iterator.

Printing an Iterator<Item = Result<(String, String)>> similar to the example above is a bit more complicated:

for result in envy::to_iter(&Config::default())? {
    let (key, value) = result?;
    println!("{key}={value:?}");
}

or when ignoring Err values:

for (key, value) in envy::to_iter(&Config::default()).filter_map(Result::ok) {
    println!("{key}={value:?}");
}

Not adding anything to envy

There's definitely an argument to keep envy as simple as possible.
I'm really curious, what other people think about this idea.
Maybe there are simpler solutions that I've overlooked.

@JonasJebing
Copy link
Author

I updated the issue with more alternatives ("Write a custom Serializer" and "Not adding anything to envy").

Note that generally I would be willing to write a PR for this feature myself 🙂

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

No branches or pull requests

1 participant