Skip to content

Commit 6f95126

Browse files
Accept owned variant keys for Decoded<Strkey> (#125)
1 parent 1115608 commit 6f95126

3 files changed

Lines changed: 56 additions & 4 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ crate-git-revision = "0.0.9"
2828
[dev-dependencies]
2929
proptest ="1.0.0"
3030
serde_test = "1.0.177"
31+
serde_json = "1"
3132

3233
[dependencies]
3334
data-encoding = { version = "2.6.0", default-features = false }

src/strkey.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,16 @@ mod strkey_decoded_serde_impl {
193193
}
194194

195195
fn visit_map<M: MapAccess<'de>>(self, mut map: M) -> Result<Self::Value, M::Error> {
196-
let key: &str = map
196+
// Read the variant key as an owned `String`, not a borrowed
197+
// `&str`. Deserializers that don't borrow from a contiguous
198+
// input buffer — e.g. `serde_json::from_value` /
199+
// `from_reader`, and most non-JSON formats — yield owned
200+
// keys that cannot be borrowed as `&str` and would fail here.
201+
let key: alloc::string::String = map
197202
.next_key()?
198203
.ok_or_else(|| de::Error::custom("expected a variant key"))?;
199204

200-
let strkey = match key {
205+
let strkey = match key.as_str() {
201206
"public_key_ed25519" => {
202207
let Decoded(inner) = map.next_value()?;
203208
Strkey::PublicKeyEd25519(inner)
@@ -232,7 +237,7 @@ mod strkey_decoded_serde_impl {
232237
}
233238
_ => {
234239
return Err(de::Error::unknown_variant(
235-
key,
240+
&key,
236241
&[
237242
"public_key_ed25519",
238243
"pre_auth_tx",
Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![cfg(feature = "cli")]
1+
#![cfg(feature = "serde-decoded")]
22

33
use stellar_strkey::{ed25519, *};
44

@@ -123,6 +123,52 @@ fn test_ed25519_signed_payload() {
123123
);
124124
}
125125

126+
// Regression tests for deserializing `Decoded<Strkey>` from deserializers that
127+
// yield owned (rather than borrowed) string keys. `serde_json::from_str`
128+
// borrows the variant key directly from the input buffer, but `from_value` and
129+
// `from_reader` cannot, so the map visitor must accept an owned key. The
130+
// `encode` CLI is one consumer that hits this, via `from_value`. See issue
131+
// #124.
132+
133+
#[test]
134+
fn test_decode_strkey_from_value() {
135+
let value = serde_json::json!({
136+
"public_key_ed25519": "3330317ec241d79943bb9aa7c8ea5f8b89f9c6ea351fe03f8ec3d1127137d484",
137+
});
138+
let Decoded(strkey): Decoded<Strkey> = serde_json::from_value(value).unwrap();
139+
assert!(matches!(strkey, Strkey::PublicKeyEd25519(_)));
140+
}
141+
142+
#[test]
143+
fn test_decode_strkey_from_reader() {
144+
// `from_reader` consumes a stream and cannot borrow keys from the input.
145+
let json = r#"{"public_key_ed25519":"3330317ec241d79943bb9aa7c8ea5f8b89f9c6ea351fe03f8ec3d1127137d484"}"#;
146+
let Decoded(strkey): Decoded<Strkey> = serde_json::from_reader(json.as_bytes()).unwrap();
147+
assert!(matches!(strkey, Strkey::PublicKeyEd25519(_)));
148+
}
149+
150+
#[test]
151+
fn test_decode_strkey_from_value_nested_variant() {
152+
// A compound variant (nested object) exercised through the owned-key path.
153+
let value = serde_json::json!({
154+
"signed_payload_ed25519": {
155+
"ed25519": "0000000000000000000000000000000000000000000000000000000000000000",
156+
"payload": "01020304",
157+
}
158+
});
159+
let Decoded(strkey): Decoded<Strkey> = serde_json::from_value(value).unwrap();
160+
assert!(matches!(strkey, Strkey::SignedPayloadEd25519(_)));
161+
}
162+
163+
#[test]
164+
fn test_roundtrip_public_key_via_value() {
165+
// Serialize to a `serde_json::Value`, then deserialize back via `from_value`.
166+
let original = Strkey::PublicKeyEd25519(ed25519::PublicKey([7u8; 32]));
167+
let value = serde_json::to_value(Decoded(&original)).unwrap();
168+
let Decoded(deserialized): Decoded<Strkey> = serde_json::from_value(value).unwrap();
169+
assert_eq!(original, deserialized);
170+
}
171+
126172
#[test]
127173
fn test_roundtrip_muxed_account() {
128174
let original = Strkey::MuxedAccountEd25519(ed25519::MuxedAccount {

0 commit comments

Comments
 (0)