Welcome to Valu3 - the ultimate, flexible, and powerful library for manipulating diverse data types in your Rust projects. Say goodbye to the complexity of handling numbers, strings, arrays, objects, and datetime values. Valu3 is here to make your life easier!
Valu3 is designed to make data manipulation tasks in Rust a breeze. By combining a wide range of features and a consistent API, it simplifies data handling in Rust projects while maximizing productivity.
Join the Valu3 revolution and experience the future of data manipulation in Rust! π
β‘ Get Started with Valu3 Today! β‘
Here are some examples of how to use the Valu3:
Value)Valu3 now exposes zero-copy converters between Serde Serialize/Deserialize types and Value, implemented using Serdeβs Serializer/Deserializer traits (no textual intermediate like serde_json). Use these when you need to convert Rust structs/enums/collections directly to Value and back.
Highlights
"MyVariant".{"Variant": value} or {"TupleVariant": [1,2]} or {"StructVariant": {"a":1}}.API
valu3::serde_value::to_value<T: Serialize>(&T) -> Result<Value, Error> β serialize a T directly into a Value.valu3::serde_value::from_value<T: DeserializeOwned>(&Value) -> Result<T, Error> β deserialize a Value into T.Example
use valu3::prelude::*;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum E {
Unit,
Newtype(String),
Tuple(i32, i32),
Struct { a: i32, b: String },
}
let v = E::Struct { a: 1, b: "x".to_string() };
let value = valu3::serde_value::to_value(&v).unwrap();
// value will be { "Struct": { "a": 1, "b": "x" } }
let back: E = valu3::serde_value::from_value(&value).unwrap();
assert_eq!(v, back);
Notes & limitations
["Variant", {...}]) is not supported; file an issue if you need it.use valu3::prelude::*;
let string_value = "hello".to_value();
let number_value = 42.to_value();
let boolean_value = true.to_value();
let null_value = Value::Null;
let undefined_value = Value::Undefined;
let mut datetime_value = DateTime::from("2023-04-05T00:00:00Z").to_value();
string_value.as_string();
number_value.get_i32();
assert_eq!(boolean_value, true);
assert_eq!(null_value, Value::Null);
assert_eq!(undefined_value, Value::Undefined);
datetime_value.add_days(1);
To start using the Valu3 in your Rust project, simply add the following line to your Cargo.toml file:
[dependencies]
valu3 = "0.8"
Then, you can import the library in your code like this:
use valu3::prelude::*;
//...
let pi = 3.14.to_value();
Valu3 provides a comprehensive type system through the Value enum, which can represent eight fundamental data types:
StringB)The String type in Valu3 provides enhanced string manipulation capabilities.
Key Methods:
as_string() - Get the String valueto_uppercase() - Convert to uppercaseto_lowercase() - Convert to lowercasetrim() - Remove whitespacereplace() - Replace substringsconcat() - Concatenate stringslen() - Get string lengthExample:
use valu3::prelude::*;
fn main() {
// Creating strings
let text = "Hello, World!".to_value();
let mut name = Value::String(StringB::from("Alice"));
// String operations
if let Value::String(s) = &text {
println!("Original: {}", s.as_string());
println!("Uppercase: {}", s.to_uppercase().as_string());
println!("Lowercase: {}", s.to_lowercase().as_string());
}
// More operations
let trimmed = " spaces ".to_value();
if let Value::String(s) = &trimmed {
println!("Trimmed: '{}'", s.trim().as_string());
}
// Replace and concat
let greeting = "Hello, NAME!".to_value();
if let Value::String(s) = &greeting {
let personalized = s.replace("NAME", "Bob");
println!("Replaced: {}", personalized.as_string());
let extended = personalized.concat(" How are you?");
println!("Concatenated: {}", extended.as_string());
}
}
Supports all Rust numeric types with automatic type detection and conversion.
Supported Types:
u8, u16, u32, u64, u128i8, i16, i32, i64, i128f32, f64Key Methods:
get_[type]() - Get value as specific type (returns Option)set_[type]() - Set value as specific typeis_[type]() - Check if value is specific typeis_integer() - Check if integeris_float() - Check if floatis_positive() / is_negative() - Check signExample:
use valu3::prelude::*;
fn main() {
// Creating numbers
let int_value = 42.to_value();
let float_value = 3.14159.to_value();
let negative = (-100).to_value();
// Type checking
println!("42 is integer: {}", int_value.as_number().unwrap().is_integer());
println!("3.14 is float: {}", float_value.as_number().unwrap().is_float());
// Getting values
if let Some(num) = int_value.as_number() {
println!("As i32: {:?}", num.get_i32());
println!("As f64: {:?}", num.get_f64());
}
// Setting values
let mut dynamic_num = Value::Number(Number::default());
dynamic_num.set_u64(1000000);
println!("Set to u64: {:?}", dynamic_num.get_u64());
// Sign checking
if let Some(num) = negative.as_number() {
println!("-100 is negative: {}", num.is_negative());
}
}
Simple true/false values.
Example:
use valu3::prelude::*;
fn main() {
let is_active = true.to_value();
let is_complete = Value::Boolean(false);
// Checking boolean values
if let Value::Boolean(b) = is_active {
println!("Active status: {}", b);
}
// Using in conditions
match is_complete {
Value::Boolean(true) => println!("Task completed!"),
Value::Boolean(false) => println!("Task pending..."),
_ => println!("Not a boolean"),
}
}
Ordered collection of Value items.
Key Methods:
push() - Add element to endpop() - Remove and return last elementget() - Get element by indexget_mut() - Get mutable reference by indexlen() - Get array lengthis_empty() - Check if emptyExample:
use valu3::prelude::*;
fn main() {
// Creating arrays
let mut numbers = vec![1, 2, 3, 4, 5].to_value();
let mixed = json!(["text", 42, true, null]);
// Array operations
if let Value::Array(arr) = &mut numbers {
arr.push(6.to_value());
println!("Array length: {}", arr.len());
// Accessing elements
if let Some(first) = arr.get(0) {
println!("First element: {}", first);
}
// Removing elements
if let Some(last) = arr.pop() {
println!("Popped: {}", last);
}
}
// Iterating
if let Value::Array(arr) = &mixed {
for (index, value) in arr.values.iter().enumerate() {
println!("Index {}: {}", index, value);
}
}
}
Key-value mappings using either HashMap or BTreeMap.
Key Methods:
insert() - Insert key-value pairget() - Get value by keyget_mut() - Get mutable reference by keyremove() - Remove key-value paircontains_key() - Check if key existskeys() - Get all keysvalues() - Get all valueslen() - Get number of pairsExample:
use valu3::prelude::*;
fn main() {
// Creating objects
let mut person = json!({
"name": "Alice",
"age": 30,
"email": "alice@example.com"
});
// Accessing values
if let Some(name) = person.get("name") {
println!("Name: {}", name);
}
// Modifying objects
person.insert("city", "New York".to_value());
person.insert("age", 31.to_value()); // Update existing
// Checking keys
if let Value::Object(obj) = &person {
println!("Has email: {}", obj.contains_key(&"email"));
println!("Object size: {}", obj.len());
// Iterate over keys
for key in obj.keys() {
println!("Key: {}", key);
}
}
// Remove values
if let Value::Object(obj) = &mut person {
if let Some(removed) = obj.remove(&"email") {
println!("Removed email: {}", removed);
}
}
}
Represents dates, times, or combined datetime values.
Variants:
Date(NaiveDate) - Date without timezoneTime(NaiveTime) - Time without dateDateTime(ChDateTime<Utc>) - Full datetime with timezoneKey Methods:
year(), month(), day() - Date componentshour(), minute(), second() - Time componentsto_iso8601() - Format as ISO 8601to_rfc3339() - Format as RFC 3339add_duration() - Add time durationnow() - Current datetimeExample:
use valu3::prelude::*;
fn main() {
// Creating datetime values
let now = DateTime::now().to_value();
let specific_date = DateTime::from("2024-01-15T10:30:00Z").to_value();
let date_only = DateTime::from_ymd_opt(2024, 12, 25).to_value();
// Accessing components
if let Value::DateTime(dt) = &specific_date {
println!("Year: {:?}", dt.year());
println!("Month: {:?}", dt.month());
println!("Hour: {:?}", dt.hour());
println!("ISO 8601: {}", dt.to_iso8601());
}
// Date arithmetic
if let Value::DateTime(dt) = &date_only {
let tomorrow = dt.add_duration(chrono::Duration::days(1));
if let Some(next_day) = tomorrow {
println!("Tomorrow: {}", next_day);
}
}
}
Represent absence or uninitialized values.
Example:
use valu3::prelude::*;
fn main() {
let null_value = Value::Null;
let undefined_value = Value::Undefined;
// Checking for null/undefined
println!("Is null: {}", null_value.is_null());
println!("Is undefined: {}", undefined_value.is_undefined());
// Pattern matching
match null_value {
Value::Null => println!("Value is null"),
Value::Undefined => println!("Value is undefined"),
_ => println!("Value has content"),
}
// JSON representation
println!("Null as JSON: {}", null_value.to_json(JsonMode::Compact));
println!("Display: {}", undefined_value);
}
use valu3::prelude::*;
fn main() {
// Building a complex data structure
let mut database = json!({
"users": [
{
"id": 1,
"name": "Alice",
"active": true,
"roles": ["admin", "user"],
"metadata": {
"created_at": "2024-01-01T00:00:00Z",
"last_login": null
}
},
{
"id": 2,
"name": "Bob",
"active": false,
"roles": ["user"],
"metadata": {
"created_at": "2024-01-15T00:00:00Z",
"last_login": "2024-01-20T10:30:00Z"
}
}
],
"settings": {
"max_users": 100,
"allow_registration": true
}
});
// Accessing nested data
if let Some(users) = database.get("users") {
if let Value::Array(user_array) = users {
println!("Total users: {}", user_array.len());
// Process each user
for user in &user_array.values {
if let Some(name) = user.get("name") {
println!("User: {}", name);
}
}
}
}
// Modifying nested data
if let Some(settings) = database.get_mut("settings") {
settings.insert("maintenance_mode", false.to_value());
}
}
use valu3::prelude::*;
fn main() {
// Converting between different representations
let data = json!({
"temperature": "23.5",
"count": "42",
"enabled": "true",
"items": "[1,2,3]"
});
// Parse string values to appropriate types
if let Some(temp_str) = data.get("temperature") {
if let Value::String(s) = temp_str {
let temp_float: f64 = s.as_string().parse().unwrap();
println!("Temperature: {}Β°C", temp_float);
}
}
// Convert JSON string to Value
let json_str = r#"{"name":"Product","price":29.99}"#;
let parsed = Value::payload_to_value(json_str).unwrap();
println!("Parsed: {}", parsed.to_json(JsonMode::Compact));
// Value to different formats
let product = json!({
"id": 123,
"name": "Widget",
"price": 19.99,
"in_stock": true
});
// To JSON
println!("JSON: {}", product.to_json(JsonMode::Indented));
// To YAML (if feature enabled)
// println!("YAML: {}", product.to_yaml());
}
use valu3::prelude::*;
fn validate_user(user: &Value) -> Result<(), String> {
// Check required fields
if !user.is_object() {
return Err("User must be an object".to_string());
}
// Validate email
match user.get("email") {
Some(email) if email.is_string() => {
let email_str = email.as_string_b().unwrap().as_string();
if !email_str.contains('@') {
return Err("Invalid email format".to_string());
}
},
_ => return Err("Email is required and must be a string".to_string()),
}
// Validate age
if let Some(age) = user.get("age") {
if let Some(num) = age.as_number() {
if let Some(age_val) = num.get_i32() {
if age_val < 0 || age_val > 150 {
return Err("Age must be between 0 and 150".to_string());
}
}
}
}
Ok(())
}
fn main() {
let valid_user = json!({
"email": "user@example.com",
"age": 25,
"name": "John Doe"
});
let invalid_user = json!({
"email": "not-an-email",
"age": 200
});
match validate_user(&valid_user) {
Ok(_) => println!("β Valid user"),
Err(e) => println!("β Invalid user: {}", e),
}
match validate_user(&invalid_user) {
Ok(_) => println!("β Valid user"),
Err(e) => println!("β Invalid user: {}", e),
}
}
use valu3::prelude::*;
fn merge_objects(base: &mut Value, updates: &Value) {
if let (Value::Object(base_obj), Value::Object(updates_obj)) = (base, updates) {
for (key, value) in updates_obj.keys().zip(updates_obj.values()) {
base_obj.insert(key.clone(), value.clone());
}
}
}
fn filter_array(array: &Value, predicate: impl Fn(&Value) -> bool) -> Value {
if let Value::Array(arr) = array {
let filtered: Vec<Value> = arr.values.iter()
.filter(|v| predicate(v))
.cloned()
.collect();
return filtered.to_value();
}
Value::Array(Array::new())
}
fn main() {
// Merging objects
let mut config = json!({
"host": "localhost",
"port": 8080
});
let overrides = json!({
"port": 3000,
"debug": true
});
merge_objects(&mut config, &overrides);
println!("Merged config: {}", config);
// Filtering arrays
let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].to_value();
let evens = filter_array(&numbers, |v| {
if let Some(num) = v.as_number() {
if let Some(n) = num.get_i32() {
return n % 2 == 0;
}
}
false
});
println!("Even numbers: {}", evens);
}
use valu3::prelude::*;
fn main() {
// The json! macro supports all JSON syntax
let config = json!({
"application": {
"name": "MyApp",
"version": "1.0.0",
"features": [
"auth",
"api",
"dashboard"
],
"settings": {
"theme": "dark",
"language": "en",
"notifications": true
}
},
"database": {
"host": "localhost",
"port": 5432,
"ssl": false,
"pools": {
"min": 5,
"max": 20
}
},
"cache": null,
"debug": true
});
// Variables in json! macro
let app_name = "MyService";
let version = 2;
let is_production = false;
let service = json!({
"service": app_name,
"version": version,
"production": is_production,
"endpoints": [
"/api/v1",
"/api/v2"
]
});
println!("Service config: {}", service.to_json(JsonMode::Compact));
}
Valu3 natively has conversions for famous data types like json, yaml and xml. Furthermore with valu3-derive you are able to transform struct to Value by applying the to_value() method generated by the ToValue derive macros. This is an example on converting struct to Value and Value to other payload data types.
use valu3::prelude:*;
#[derive(ToValue, FromValue, Default)]
struct MyStruct {
id: u32,
name: String,
tags: Vec<String>
}
fn main(){
let my_struct = MyStruct::default();
let value = my_struct.to_value();
assert_eq!(my_struct, MyStruct::from_value(value));
}
If your focus is only on using Valu3 for conversion only, use the ToJson macro.
use valu3::prelude:*;
#[derive(ToJson, Default)]
struct MyStruct {
id: u32,
name: String,
tags: Vec<String>
}
fn main(){
let my_struct = MyStruct::default();
let json = my_struct.to_json();
println!("{}", json); // print json string
}
Vale3 is able to recognize a payload string, identify and convert it to Value, follow the example:
use valu3::prelude:*;
fn main(){
let boolean = Value::payload_to_value("true").unwrap();
let float = Value::payload_to_value("3.14").unwrap();
let json = Value::payload_to_value(r#"{"item": 3.14}"#).unwrap();
let array = Value::payload_to_value(r#"[1,2,3]"#).unwrap();
let null = Value::payload_to_value("null").unwrap();
let string = Value::payload_to_value(r#""123""#).unwrap();
assert_eq!(boolean, true.to_value());
assert_eq!(float, 3.14.to_value());
assert_eq!(json, Value::from(vec![("item", 3.14)]));
assert_eq!(array, vec![1, 2, 3].to_value());
assert_eq!(null, Value::Null);
assert_eq!(string, "123".to_value());
}
If you find a bug or have a suggestion for a new feature, please open an issue on the GitHub repository.
If you would like to contribute to the project, please feel free to submit a pull request. Before submitting a pull request, please make sure that your code adheres to the projectβs style guidelines and passes all tests.
~ Weβre constantly working to improve and expand the capabilities of Valu3, making it even more powerful and versatile.
By keeping track of the projectβs progress, you can stay informed about new features in development and planned improvements. This will allow you to make the most of Valu3 in your Rust projects and prepare for future updates.
Our commitment is to make Valu3 the ultimate data manipulation solution in Rust. Your input is invaluable! Feel free to join the discussions, share your ideas, and contribute to the project as it evolves.
Join us in the ongoing journey to refine and expand Valu3! π
This project is licensed under the Apache 2.0 License. See the LICENSE file for more information.