Comments (14)
Unless I'm missing something, it doesn't seem like that approach would allow the user to specify the config to use when serializing.
from rust-base64.
Just the base64::STANDARD config would be a good start. Is that the same encoding Go does by default for bytes in JSON?
package main
import (
"encoding/json"
"fmt"
)
func main() {
type E struct {
Bytes []byte
}
j, err := json.Marshal(E { Bytes: []byte("data0123456789") })
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
A configurable variation may involve serialize
and deserialize
helpers on Config.
static MY_CUSTOM = base64::Config {
char_set: /* ... */,
pad: /* ... */,
strip_whitespace: /* ... */,
line_wrap: /* ... */,
};
#[derive(Serialize, Deserialize)]
struct MyBytes {
#[serde(with = "base64::URL_SAFE")]
a: Vec<u8>,
#[serde(with = "MY_CUSTOM")]
b: Vec<u8>,
}
from rust-base64.
Hmm... It seems like this could be solved without any magic strings representing the different configs, etc, by simply providing a snippet of sample code that people could modify for their own purposes akin to what was in the json example you linked to. I'd like to stay away from baking in magic strings or any other sort of pseudo-API, or embedding the standard config as the only realistic choice. (For instance, for most users, what they probably want is standard with no padding since it saves a byte or two.)
In general, I think that serialization decisions should be made by the application, not by libraries they depend on. I would rather that applications make explicit (but not overly burdensome) choices for how they want to serialize, rather than just going with what their particular framework spoon-feeds them. (That's how you end up with reimplementations of PHP serialization in other languages to interop with crappy web services...) For possibly related context on where I'm coming from on this, I had a discussion about the merits of the serde semi-magical approach on another project.
from rust-base64.
Thanks! I haven't had a chance to read the thread you linked but I am unclear what it is we disagree on, if anything.
I'd like to stay away from baking in magic strings or any other sort of pseudo-API
When you say magic strings, is that referring to with = "base64::URL_SAFE"
? That is just the path to base64::URL_SAFE
. I guess I don't normally conceptualize named variables / modules / statics as magic strings -- not any more than the word "base64" is a magic string when I write extern crate base64
, for example.
I would rather that applications make explicit (but not overly burdensome) choices for how they want to serialize
Okay! I think this is exactly what MY_CUSTOM
is for in my previous comment.
from rust-base64.
I see what you mean -- more my lack of real world use of serde showing than any real disagreement, I think. The stringy nature is just the way we have to expose the serializer to the code gen machinery, then? Regrettable, but at least it's still checked at compile time.
It seems like a conflation of concerns to bolt this onto Config
, though. A config is just a config, so it would make more sense to me to have a separate struct to handle the serde
integration that has a Config
member. However, I'm not really clear on what's going on with the with
customization. What is the thing that gets pointed to supposed to be? I saw in your json example it's a module, but I clicked around a little and didn't see where that's documented.
from rust-base64.
OK, found https://serde.rs/field-attrs.html. I'm not sure I'm understanding this correctly, though, since it looks like with
has to be a module, but in your example above you're using a Config
. Can you go into more detail about the extent of what you can do with with
?
from rust-base64.
It doesn't matter whether with
is a module or crate or const or type or whatever else. We take whatever "thing"
you write and invoke thing::serialize
to serialize the field and thing::deserialize
to deserialize the field, as if those functions were the implementation of Serialize and Deserialize for the field's type. I think using a base64 config to configure how a field is represented in base64 is concise, expressive, sufficiently explicit, and intuitive.
from rust-base64.
Hmm... still looks like a violation of SOLID to me. I don't like having to take a route that the consumer of the library couldn't feasibly replace; that's a design smell.
Anyway, be that as it may, can you comment on https://github.com/alicemaz/rust-base64/compare/serde?expand=1? I think I'm doing more or less the same thing as your CUSTOM
approach above, but I get compiler woes:
error[E0433]: failed to resolve. Use of undeclared type or module `B64`
--> src/serde.rs:54:14
|
54 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^ Use of undeclared type or module `B64`
from rust-base64.
Oh I see, the generated code blindly invokes B64::serialize(/* ... */)
instead of what we would want which is B64.serialize(/* ... */)
. I filed serde-rs/serde#1059 to follow up.
In the meantime, top-level base64::serialize
and base64::deserialize
functions would be helpful. Those would be usable concisely as #[serde(with = "base64")]
and assume a default configuration, like how base64::encode
and base64::decode
assume the STANDARD configuration. And when necessary, the user can continue to handle custom configurations the way we did in serde-rs/json#360.
from rust-base64.
Sorry to be so contrary, but I don't want to add an awkward interim solution that I would then have to deprecate later (or maintain forever). It also creates a default choice that isn't necessarily suitable for everyone. For instance, I suspect that many users will in fact want STANDARD_NO_PAD
, not STANDARD
to save 1 byte on average. (Padding is entirely unnecessary; un-padded base64 can be decoded just fine, and having padding just creates an opportunity to have done it wrong.)
However, I don't want to leave serde users high and dry, so I slapped together this band-aid to ease creating the type wrapper around a config: https://github.com/marshallpierce/base64-serde/blob/master/src/lib.rs. I think this should be a good-enough solution until serde-rs/serde#1059 is solved. (BTW, I'm a macro noob, so happy to take feedback on my macro, etc.) Anyway, if that looks reasonable, I'll go ahead and write some docs and publish that. I made it a separate project so that it can be more conveniently abandoned once we have a better approach available.
from rust-base64.
Base64-serde looks good to me. I filed some issues but nicely done. Thanks for putting that together!
49% of crates that depend on base64 also depend on serde so this will be a big help.
It also creates a default choice that isn't necessarily suitable for everyone.
Hmm, how would this be worse than base64::encode and base64::decode choosing a default behavior?
I suspect that many users will in fact want
STANDARD_NO_PAD
, notSTANDARD
to save 1 byte on average.
I think if STANDARD with padding is good enough for Go to use for all byte slices by default, it's good enough for us. It seems like a safe default that has probably better interoperability with remote systems than STANDARD_NO_PAD.
from rust-base64.
Thanks for the feedback on base64-serde; I'll work on what you've suggested.
Hmm, how would this be worse than base64::encode and base64::decode choosing a default behavior?
It's not, but I didn't write that API, and I wouldn't have chosen to make it available if I was involved in the crate then. :)
from rust-base64.
https://crates.io/crates/base64-serde is now a thing. Anything else to do for this issue?
from rust-base64.
LGTM, thank you!
from rust-base64.
Related Issues (20)
- Restore base64::{encode, decode} functions HOT 11
- Thank you
- How do I change the padding character? HOT 1
- Using this crate easier HOT 2
- DecoderReader accepts incorrect input HOT 2
- Design choices HOT 5
- How come I can't decode this string? HOT 1
- `DecoderReader` probably should accept `BufRead` instead of `Read` HOT 1
- make Alphabet::from_str_unchecked public HOT 3
- Replacement for base64::decode()? HOT 12
- How to generate the base64 format like openssl command HOT 3
- `DecoderReader` does not respect `with_decode_allow_trailing_bits` HOT 4
- how to encode image bytes to string? HOT 1
- GeneralPurpose engine should implement Clone and Debug HOT 6
- Make `Alphabet::from_str_unchecked` `pub const unsafe` HOT 5
- Calling `EncoderStringWriter::write` successively does not equal `EncoderStringWriter::write_all` HOT 2
- Make `encoded_len` const HOT 3
- Add encode_vec() HOT 4
- Question: best way to access inner field values HOT 5
- SIMD support? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rust-base64.