scale_value/lib.rs
1// Copyright (C) 2022-2023 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the scale-value crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16/*!
17This crate exposes the [`Value`] type and related subtypes, which are used as the runtime
18representations of SCALE encoded data (much like `serde_json::Value` is a runtime representation
19of JSON data).
20
21[`Value`]'s can be:
22
23- Encoded and decoded from SCALE bytes via [`::scale_encode::EncodeAsType`] and [`::scale_decode::DecodeAsType`]
24 traits (or by calling [`crate::scale::decode_as_type`] and [`crate::scale::encode_as_type`]).
25- Parsed to and from strings by calling [`crate::stringify::from_str`] and [`crate::stringify::to_string`]).
26 Parsing from strings requires the `from_string` feature to be enabled.
27- Serialized and deserialized via `serde` traits (for example, to and from JSON). They can also be serialized
28 from and to other types with the relevant serde derives on. These require the `serde` feature to be enabled.
29- Accessed ergonomically via the [`At`] trait.
30*/
31#![deny(missing_docs)]
32#![no_std]
33
34extern crate alloc;
35
36#[cfg(feature = "__std")]
37extern crate std;
38
39mod at;
40mod macros;
41mod prelude;
42mod scale_impls;
43#[cfg(feature = "serde")]
44mod serde_impls;
45mod string_impls;
46mod value_type;
47
48// Traits to allow indexing into values.
49pub use at::{At, Location};
50
51// The value definition.
52pub use value_type::{BitSequence, Composite, Primitive, Value, ValueDef, Variant};
53
54/// Serializing and deserializing a [`crate::Value`] into/from other types via serde.
55#[cfg(feature = "serde")]
56pub mod serde {
57 use crate::prelude::*;
58 pub use crate::serde_impls::{DeserializerError, SerializerError, ValueSerializer};
59
60 /// Attempt to convert a [`crate::Value`] into another type via serde.
61 ///
62 /// # Examples
63 ///
64 /// Use serde to convert a value into a built-in type:
65 ///
66 /// ```rust
67 /// use scale_value::Value;
68 ///
69 /// let value = Value::unnamed_composite(vec![
70 /// Value::u128(1),
71 /// Value::u128(2),
72 /// Value::u128(3),
73 /// ]);
74 ///
75 /// let arr: [u8; 3] = scale_value::serde::from_value(value).unwrap();
76 /// ```
77 ///
78 /// Converting values to a custom type:
79 ///
80 /// ```rust
81 /// use scale_value::Value;
82 /// use serde::{ Serialize, Deserialize };
83 ///
84 /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
85 /// enum Foo {
86 /// A { is_valid: bool, name: String },
87 /// B(u8, bool)
88 /// }
89 ///
90 /// let value1 = Value::named_variant("A", [
91 /// ("name", Value::string("James")),
92 /// ("is_valid", Value::bool(true)),
93 /// ]);
94 /// let foo1: Foo = scale_value::serde::from_value(value1).unwrap();
95 /// assert_eq!(foo1, Foo::A { is_valid: true, name: "James".into() });
96 ///
97 /// let value2 = Value::unnamed_variant("B", [
98 /// Value::u128(123),
99 /// Value::bool(true),
100 /// ]);
101 /// let foo2: Foo = scale_value::serde::from_value(value2).unwrap();
102 /// assert_eq!(foo2, Foo::B(123, true));
103 /// ```
104 pub fn from_value<'de, Ctx, T: serde::Deserialize<'de>>(
105 value: crate::Value<Ctx>,
106 ) -> Result<T, DeserializerError> {
107 T::deserialize(value)
108 }
109
110 /// Attempt to convert some type into a [`crate::Value`] via serde.
111 ///
112 /// # Examples
113 ///
114 /// Convert a built-in array of values into a [`crate::Value`]:
115 ///
116 /// ```rust
117 /// use scale_value::Value;
118 ///
119 /// let arr = [1u8, 2u8, 3u8];
120 ///
121 /// let val = scale_value::serde::to_value(arr).unwrap();
122 /// assert_eq!(val, Value::unnamed_composite([
123 /// Value::u128(1),
124 /// Value::u128(2),
125 /// Value::u128(3),
126 /// ]));
127 /// ```
128 ///
129 /// Converting some custom type to a [`crate::Value`]:
130 ///
131 /// ```rust
132 /// use scale_value::Value;
133 /// use serde::{ Serialize, Deserialize };
134 ///
135 /// #[derive(Serialize, Deserialize, PartialEq, Debug)]
136 /// enum Foo {
137 /// A { is_valid: bool, name: String },
138 /// B(u8, bool)
139 /// }
140 ///
141 /// let foo = Foo::A { is_valid: true, name: "James".into() };
142 ///
143 /// let value = scale_value::serde::to_value(foo).unwrap();
144 /// assert_eq!(value, Value::named_variant("A", [
145 /// ("is_valid", Value::bool(true)),
146 /// ("name", Value::string("James")),
147 /// ]));
148 /// ```
149 pub fn to_value<T: serde::Serialize>(ty: T) -> Result<crate::Value<()>, SerializerError> {
150 ty.serialize(ValueSerializer)
151 }
152}
153
154/// Encoding and decoding SCALE bytes into a [`crate::Value`].
155///
156/// # Exmaple
157///
158/// Given some known metadata type ID, encode and decode some [`crate::Value`]
159/// to SCALE bytes.
160///
161/// ```rust
162/// # fn make_type<T: scale_info::TypeInfo + 'static>() -> (u32, scale_info::PortableRegistry) {
163/// # let m = scale_info::MetaType::new::<T>();
164/// # let mut types = scale_info::Registry::new();
165/// # let id = types.register_type(&m);
166/// # let portable_registry: scale_info::PortableRegistry = types.into();
167/// # (id.id(), portable_registry)
168/// # }
169/// # let (type_id, registry) = make_type::<Foo>();
170/// use scale_value::Value;
171///
172/// // Imagine we have a `registry` (of type [`scale_info::PortableRegistry`]) containing this type,
173/// // and a `type_id` (a `u32`) pointing to it in the registry.
174/// #[derive(scale_info::TypeInfo)]
175/// enum Foo {
176/// A { is_valid: bool, name: String }
177/// }
178///
179/// // Given that, we can encode/decode something with that shape to/from SCALE bytes:
180/// let value = Value::named_variant("A", [
181/// ("is_valid", Value::bool(true)),
182/// ("name", Value::string("James")),
183/// ]);
184///
185/// // Encode the Value to bytes:
186/// let mut bytes = Vec::new();
187/// scale_value::scale::encode_as_type(&value, type_id, ®istry, &mut bytes).unwrap();
188///
189/// // Decode the bytes back into a matching Value.
190/// // This value contains contextual information about which type was used
191/// // to decode each part of it, which we can throw away with `.remove_context()`.
192/// let new_value = scale_value::scale::decode_as_type(&mut &*bytes, type_id, ®istry).unwrap();
193///
194/// assert_eq!(value, new_value.remove_context());
195/// ```
196pub mod scale {
197 use crate::prelude::*;
198 use scale_decode::FieldIter;
199 use scale_encode::EncodeAsType;
200
201 pub use crate::scale_impls::{DecodeError, ValueVisitor};
202 pub use scale_encode::Error as EncodeError;
203 pub use scale_type_resolver::TypeResolver;
204
205 /// Attempt to decode some SCALE encoded bytes into a value, by providing a pointer
206 /// to the bytes (which will be moved forwards as bytes are used in the decoding),
207 /// a type ID, and a type registry from which we'll look up the relevant type information.
208 pub fn decode_as_type<R>(
209 data: &mut &[u8],
210 ty_id: R::TypeId,
211 types: &R,
212 ) -> Result<crate::Value<R::TypeId>, DecodeError>
213 where
214 R: TypeResolver,
215 R::TypeId: Clone,
216 {
217 crate::scale_impls::decode_value_as_type(data, ty_id, types)
218 }
219
220 /// Attempt to decode some SCALE encoded bytes into multiple values, by providing a pointer
221 /// to the bytes (which will be moved forwards as bytes are used in the decoding),
222 /// and an iterator of fields, where each field contains a type ID and optionally a field name.
223 pub fn decode_as_fields<'resolver, R>(
224 input: &mut &[u8],
225 fields: &mut dyn FieldIter<'resolver, R::TypeId>,
226 types: &'resolver R,
227 ) -> Result<crate::Composite<R::TypeId>, DecodeError>
228 where
229 R: TypeResolver,
230 R::TypeId: Clone,
231 {
232 crate::scale_impls::decode_composite_as_fields(input, fields, types)
233 }
234
235 /// Attempt to encode some [`crate::Value<T>`] into SCALE bytes, by providing a pointer to the
236 /// type ID that we'd like to encode it as, a type registry from which we'll look
237 /// up the relevant type information, and a buffer to encode the bytes to.
238 pub fn encode_as_type<R: TypeResolver, T>(
239 value: &crate::Value<T>,
240 ty_id: R::TypeId,
241 types: &R,
242 buf: &mut Vec<u8>,
243 ) -> Result<(), EncodeError> {
244 value.encode_as_type_to(ty_id, types, buf)
245 }
246
247 /// A visitor and function to decode some bytes into a [`crate::Value`] while tracing the current
248 /// decoding state so that a more detailed error can be returned in the event of a failure.
249 pub mod tracing {
250 pub use crate::scale_impls::{TraceDecodingError, TraceDecodingVisitor};
251
252 /// Decode a value using the [`TraceDecodingVisitor`], which internally keeps track of the current decoding state, and as
253 /// a result hands back a much more detailed error than [`crate::scale::decode_as_type()`] if decoding fails.
254 ///
255 /// One approach is to use the standard visitor for decoding on the "happy path", and if you need more information about
256 /// the decode error, to try decoding the same bytes again using this function to obtain more information about what failed.
257 pub fn decode_as_type<R>(
258 data: &mut &[u8],
259 ty_id: R::TypeId,
260 types: &R,
261 ) -> Result<crate::Value<R::TypeId>, TraceDecodingError<crate::Value<R::TypeId>>>
262 where
263 R: scale_type_resolver::TypeResolver,
264 {
265 scale_decode::visitor::decode_with_visitor(
266 data,
267 ty_id,
268 types,
269 TraceDecodingVisitor::new(),
270 )
271 }
272 }
273}
274
275/// Converting a [`crate::Value`] to or from strings.
276pub mod stringify {
277 use crate::prelude::*;
278
279 pub use crate::string_impls::ToWriterBuilder;
280 #[cfg(feature = "from-string")]
281 pub use crate::string_impls::{
282 FromStrBuilder, ParseBitSequenceError, ParseCharError, ParseComplexError, ParseError,
283 ParseErrorKind, ParseNumberError, ParseStringError,
284 };
285
286 /// This module provides custom parsers that work alongside [`crate::stringify::from_str_custom`]
287 /// and extend the syntax to support parsing common formats into [`crate::Value`]'s. See
288 /// [`crate::stringify::from_str_custom`] for a usage example.
289 #[cfg(feature = "from-string")]
290 pub mod custom_parsers {
291 #[cfg(feature = "parser-ss58")]
292 pub use crate::string_impls::parse_ss58;
293 pub use crate::string_impls::{parse_hex, ParseHexError};
294 }
295
296 /// This module provides custom formatters that work alongside [`crate::stringify::to_writer_custom`]
297 /// and allow for the output to be formatted in various ways.
298 pub mod custom_formatters {
299 pub use crate::string_impls::format_hex;
300 }
301
302 /// Attempt to parse a string into a [`crate::Value<()>`], returning a tuple
303 /// consisting of a result (either the value or a [`ParseError`] containing
304 /// location and error information) and the remainder of the string that wasn't
305 /// parsed.
306 ///
307 /// # Examples
308 ///
309 /// ```rust
310 /// use scale_value::Value;
311 ///
312 /// fn to_value(str: &str) -> Value {
313 /// scale_value::stringify::from_str(str).0.unwrap()
314 /// }
315 ///
316 /// // Primitive values:
317 /// assert_eq!(to_value("1"), Value::u128(1));
318 /// assert_eq!(to_value("-1"), Value::i128(-1));
319 /// assert_eq!(to_value("true"), Value::bool(true));
320 /// assert_eq!(to_value("'a'"), Value::char('a'));
321 /// assert_eq!(to_value("\"hi\""), Value::string("hi"));
322 ///
323 /// // Named composite values look a bit like rust structs:
324 /// let value = to_value("{ a: true, b: \"hello\" }");
325 /// assert_eq!(
326 /// value,
327 /// Value::named_composite(vec![
328 /// ("a", Value::bool(true)),
329 /// ("b", Value::string("hello"))
330 /// ])
331 /// );
332 ///
333 /// // Unnamed composite values look a bit like rust tuples:
334 /// let value = to_value("(true, \"hello\")");
335 /// assert_eq!(
336 /// value,
337 /// Value::unnamed_composite(vec![
338 /// Value::bool(true),
339 /// Value::string("hello")
340 /// ])
341 /// );
342 ///
343 /// // Variant values (named or unnamed) are just the above with a variant name
344 /// // prefixed:
345 /// let value = to_value("MyVariant { a: true, b: \"hello\" }");
346 /// assert_eq!(
347 /// value,
348 /// Value::named_variant(
349 /// "MyVariant",
350 /// vec![
351 /// ("a", Value::bool(true)),
352 /// ("b", Value::string("hello"))
353 /// ]
354 /// )
355 /// );
356 ///
357 /// // Bit sequences can be encoded from unnamed composites, but we have a
358 /// // compact syntax for them too:
359 /// assert_eq!(
360 /// to_value("<0101>"),
361 /// Value::bit_sequence(scale_bits::Bits::from_iter([false, true, false, true]))
362 /// );
363 /// ```
364 #[cfg(feature = "from-string")]
365 pub fn from_str(s: &str) -> (Result<crate::Value<()>, ParseError>, &str) {
366 crate::string_impls::FromStrBuilder::new().parse(s)
367 }
368
369 /// This is similar to [`from_str`], except that it returns a [`FromStrBuilder`],
370 /// which allows for some additional configuration in how strings are parsed.
371 ///
372 /// # Example
373 ///
374 /// ```rust
375 /// # // Example only runs when parser-ss58 feature is enabled:
376 /// # #[cfg(not(feature = "parser-ss58"))]
377 /// # fn main() {}
378 /// # #[cfg(feature = "parser-ss58")]
379 /// # fn main() {
380 /// #
381 /// use scale_value::Value;
382 /// use scale_value::stringify::custom_parsers;
383 ///
384 /// fn to_value(str: &str) -> Value {
385 /// scale_value::stringify::from_str_custom()
386 /// // You can write your own custom parser, but for
387 /// // this example, we just use some provided ones.
388 /// .add_custom_parser(custom_parsers::parse_hex)
389 /// // Requires the parser-ss58 feature:
390 /// .add_custom_parser(custom_parsers::parse_ss58)
391 /// .parse(str)
392 /// .0
393 /// .unwrap()
394 /// }
395 ///
396 /// // Hex strings will now be parsed into unnamed composite types
397 /// let value = to_value("(1,2,0x030405)");
398 /// assert_eq!(
399 /// value,
400 /// Value::unnamed_composite(vec![
401 /// Value::u128(1),
402 /// Value::u128(2),
403 /// Value::unnamed_composite(vec![
404 /// Value::u128(3),
405 /// Value::u128(4),
406 /// Value::u128(5),
407 /// ])
408 /// ])
409 /// );
410 ///
411 /// // ss58 addresses will also become unnamed composite types
412 /// let value = to_value(r#"{
413 /// name: "Alice",
414 /// address: 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty
415 /// }"#);
416 ///
417 /// // Manually obtain and decode the hex value for the address:
418 /// let addr: Vec<_> = hex::decode("8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48")
419 /// .unwrap()
420 /// .into_iter()
421 /// .map(|b| Value::u128(b as u128))
422 /// .collect();
423 ///
424 /// assert_eq!(
425 /// value,
426 /// Value::named_composite(vec![
427 /// ("name", Value::string("Alice")),
428 /// ("address", Value::unnamed_composite(addr))
429 /// ])
430 /// )
431 /// #
432 /// # }
433 /// ```
434 #[cfg(feature = "from-string")]
435 pub fn from_str_custom() -> FromStrBuilder {
436 crate::string_impls::FromStrBuilder::new()
437 }
438
439 /// Identical to calling `to_string()` on the [`crate::Value`], but here just
440 /// to make it a little more obvious that this is the inverse of [`from_str`].
441 ///
442 /// # Panics
443 ///
444 /// Panics if a `Primitive::U256`/`Primitive::I256` are a part of the value,
445 /// since we cannot properly format and parse those at the moment.
446 pub fn to_string<T>(value: &crate::Value<T>) -> String {
447 value.to_string()
448 }
449
450 /// Format a [`crate::Value`] to a string, writing it to the provided writer.
451 ///
452 /// # Example
453 ///
454 /// ```rust
455 /// use scale_value::{Value, value};
456 ///
457 /// let value = value!({
458 /// foo: true,
459 /// bar: "hello"
460 /// });
461 ///
462 /// // Write the ourput to a string or any other writer.
463 /// let mut s = String::new();
464 /// scale_value::stringify::to_writer(&value, &mut s).unwrap();
465 ///
466 /// assert_eq!(s, r#"{ foo: true, bar: "hello" }"#)
467 /// ```
468 pub fn to_writer<T, W: core::fmt::Write>(
469 value: &crate::Value<T>,
470 writer: W,
471 ) -> core::fmt::Result {
472 crate::string_impls::ToWriterBuilder::new().write(value, writer)
473 }
474
475 /// Format a [`crate::Value`] to a string. Several options can be configured in the
476 /// process, such as the indentation, custom formatters, printing of context, and
477 /// style (compact or spaced).
478 ///
479 /// # Example
480 ///
481 /// ```rust
482 /// use scale_value::{Value, ValueDef, Primitive, value};
483 /// use scale_value::stringify::custom_formatters::format_hex;
484 /// use core::fmt::Write;
485 ///
486 /// let value = value!({
487 /// foo: true,
488 /// bar: (1u8,2u8,3u8,4u8)
489 /// });
490 ///
491 /// let mut s = String::new();
492 ///
493 /// fn capitalise_bools<T, W: Write>(v: &Value<T>, w: &mut W) -> Option<core::fmt::Result> {
494 /// if let ValueDef::Primitive(Primitive::Bool(b)) = &v.value {
495 /// match b {
496 /// true => Some(write!(w, "TRUE")),
497 /// false => Some(write!(w, "FALSE"))
498 /// }
499 /// } else {
500 /// None
501 /// }
502 /// }
503 ///
504 /// scale_value::stringify::to_writer_custom()
505 /// .compact()
506 /// .add_custom_formatter(|v, w| format_hex(v, w))
507 /// .add_custom_formatter(|v, w| capitalise_bools(v, w))
508 /// .write(&value, &mut s);
509 ///
510 /// assert_eq!(s, r#"{foo:TRUE,bar:0x01020304}"#)
511 /// ```
512 pub fn to_writer_custom<T, W: core::fmt::Write>() -> ToWriterBuilder<T, W> {
513 crate::string_impls::ToWriterBuilder::new()
514 }
515}