mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-01-31 21:22:22 +00:00
Add tags support
This commit is contained in:
parent
aa54f1a4e6
commit
509810e87a
5 changed files with 537 additions and 63 deletions
|
@ -20,7 +20,6 @@ use std::os::raw::c_void;
|
|||
use std::ffi::CString;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
|
||||
use value::*;
|
||||
|
||||
pub struct Caps(*mut c_void);
|
||||
|
|
|
@ -42,3 +42,4 @@ pub mod log;
|
|||
pub mod value;
|
||||
pub mod caps;
|
||||
pub mod bytes;
|
||||
pub mod tags;
|
||||
|
|
222
gst-plugin/src/tags.rs
Normal file
222
gst-plugin/src/tags.rs
Normal file
|
@ -0,0 +1,222 @@
|
|||
// Copyright (C) 2016 Sebastian Dröge <sebastian@centricular.com>
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Library General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Library General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Library General Public
|
||||
// License along with this library; if not, write to the
|
||||
// Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
// Boston, MA 02110-1301, USA.
|
||||
|
||||
use std::os::raw::c_void;
|
||||
use std::fmt;
|
||||
use libc::c_char;
|
||||
use std::ffi::{CStr, CString};
|
||||
use utils::*;
|
||||
use value::*;
|
||||
|
||||
pub trait Tag {
|
||||
type TagType: ValueType;
|
||||
fn tag_name() -> &'static str;
|
||||
}
|
||||
|
||||
macro_rules! impl_tag(
|
||||
($name:ident, $t:ty, $tag:expr) => {
|
||||
pub struct $name;
|
||||
impl Tag for $name {
|
||||
type TagType = $t;
|
||||
fn tag_name() -> &'static str {
|
||||
$tag
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
impl_tag!(Title, String, "title");
|
||||
impl_tag!(Album, String, "album");
|
||||
impl_tag!(Artist, String, "artist");
|
||||
impl_tag!(Encoder, String, "encoder");
|
||||
impl_tag!(AudioCodec, String, "audio-codec");
|
||||
impl_tag!(VideoCodec, String, "video-codec");
|
||||
impl_tag!(SubtitleCodec, String, "subtitle-codec");
|
||||
impl_tag!(ContainerFormat, String, "container-format");
|
||||
// TODO: Should ideally enforce this to be ISO-639
|
||||
impl_tag!(LanguageCode, String, "language-code");
|
||||
impl_tag!(Duration, u64, "duration");
|
||||
impl_tag!(NominalBitrate, u32, "nominal-bitrate");
|
||||
|
||||
#[repr(C)]
|
||||
pub enum MergeMode {
|
||||
ReplaceAll = 1,
|
||||
Replace,
|
||||
Append,
|
||||
Prepend,
|
||||
Keep,
|
||||
KeepAll,
|
||||
}
|
||||
|
||||
pub struct TagList(*mut c_void);
|
||||
|
||||
impl TagList {
|
||||
pub fn new() -> Self {
|
||||
extern "C" {
|
||||
fn gst_tag_list_new_empty() -> *mut c_void;
|
||||
}
|
||||
|
||||
TagList(unsafe { gst_tag_list_new_empty() })
|
||||
}
|
||||
|
||||
pub fn add<T: Tag>(&mut self, value: T::TagType, mode: MergeMode)
|
||||
where Value: From<<T as Tag>::TagType>
|
||||
{
|
||||
extern "C" {
|
||||
fn gst_tag_list_add_value(list: *mut c_void,
|
||||
mode: u32,
|
||||
tag: *const c_char,
|
||||
value: *const GValue);
|
||||
}
|
||||
|
||||
let v = Value::from(value);
|
||||
let gvalue = v.to_gvalue();
|
||||
let tag_name = CString::new(T::tag_name()).unwrap();
|
||||
|
||||
unsafe {
|
||||
gst_tag_list_add_value(self.0,
|
||||
mode as u32,
|
||||
tag_name.as_ptr(),
|
||||
&gvalue as *const GValue);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get<T: Tag>(&mut self) -> Option<TypedValue<T::TagType>>
|
||||
where Value: From<<T as Tag>::TagType>
|
||||
{
|
||||
extern "C" {
|
||||
fn gst_tag_list_copy_value(value: *mut GValue,
|
||||
list: *mut c_void,
|
||||
tag: *const c_char)
|
||||
-> GBoolean;
|
||||
}
|
||||
|
||||
let mut gvalue = GValue::new();
|
||||
let tag_name = CString::new(T::tag_name()).unwrap();
|
||||
|
||||
let found = unsafe {
|
||||
gst_tag_list_copy_value(&mut gvalue as *mut GValue, self.0, tag_name.as_ptr())
|
||||
};
|
||||
|
||||
if !found.to_bool() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match Value::from_gvalue(&gvalue) {
|
||||
Some(value) => Some(TypedValue::new(value)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> String {
|
||||
extern "C" {
|
||||
fn gst_tag_list_to_string(tag_list: *mut c_void) -> *mut c_char;
|
||||
}
|
||||
|
||||
unsafe { CStr::from_ptr(gst_tag_list_to_string(self.0)).to_string_lossy().into_owned() }
|
||||
}
|
||||
|
||||
pub unsafe fn as_ptr(&self) -> *const c_void {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn make_writable(self: TagList) -> TagList {
|
||||
extern "C" {
|
||||
fn gst_mini_object_make_writable(obj: *mut c_void) -> *mut c_void;
|
||||
}
|
||||
|
||||
let raw = unsafe { gst_mini_object_make_writable(self.0) };
|
||||
|
||||
TagList(raw)
|
||||
}
|
||||
|
||||
pub fn copy(&self) -> TagList {
|
||||
extern "C" {
|
||||
fn gst_mini_object_copy(obj: *const c_void) -> *mut c_void;
|
||||
}
|
||||
unsafe { TagList(gst_mini_object_copy(self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TagList {
|
||||
fn clone(&self) -> Self {
|
||||
extern "C" {
|
||||
fn gst_mini_object_ref(mini_object: *mut c_void) -> *mut c_void;
|
||||
}
|
||||
|
||||
unsafe { TagList(gst_mini_object_ref(self.0)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TagList {
|
||||
fn drop(&mut self) {
|
||||
extern "C" {
|
||||
fn gst_mini_object_unref(mini_object: *mut c_void);
|
||||
}
|
||||
|
||||
unsafe { gst_mini_object_unref(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TagList {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use value::*;
|
||||
use std::ptr;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
fn init() {
|
||||
extern "C" {
|
||||
fn gst_init(argc: *mut c_void, argv: *mut c_void);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gst_init(ptr::null_mut(), ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add() {
|
||||
init();
|
||||
|
||||
let mut tags = TagList::new();
|
||||
assert_eq!(tags.to_string(), "taglist;");
|
||||
tags.add::<Title>("some title".into(), MergeMode::Append);
|
||||
tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append);
|
||||
assert_eq!(tags.to_string(),
|
||||
"taglist, title=(string)\"some\\ title\", duration=(guint64)120000000000;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get() {
|
||||
init();
|
||||
|
||||
let mut tags = TagList::new();
|
||||
assert_eq!(tags.to_string(), "taglist;");
|
||||
tags.add::<Title>("some title".into(), MergeMode::Append);
|
||||
tags.add::<Duration>((1000u64 * 1000 * 1000 * 120).into(), MergeMode::Append);
|
||||
|
||||
assert_eq!(*tags.get::<Title>().unwrap(), "some title");
|
||||
assert_eq!(*tags.get::<Duration>().unwrap(), (1000u64 * 1000 * 1000 * 120));
|
||||
}
|
||||
}
|
|
@ -189,6 +189,7 @@ pub fn gcd(mut a: u32, mut b: u32) -> u32 {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use num_rational::Rational32;
|
||||
|
||||
#[test]
|
||||
fn test_gcd() {
|
||||
|
@ -198,9 +199,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_f64_to_fraction() {
|
||||
assert_eq!(f64_to_fraction(2.0), Some((2, 1)));
|
||||
assert_eq!(f64_to_fraction(2.5), Some((5, 2)));
|
||||
assert_eq!(f64_to_fraction(0.127659574), Some((29013539, 227272723)));
|
||||
assert_eq!(f64_to_fraction(29.97), Some((2997, 100)));
|
||||
assert_eq!(f64_to_fraction(2.0), Some(Rational32::new(2, 1)));
|
||||
assert_eq!(f64_to_fraction(2.5), Some(Rational32::new(5, 2)));
|
||||
assert_eq!(f64_to_fraction(0.127659574),
|
||||
Some(Rational32::new(29013539, 227272723)));
|
||||
assert_eq!(f64_to_fraction(29.97), Some(Rational32::new(2997, 100)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
use libc::c_char;
|
||||
use std::os::raw::c_void;
|
||||
use std::ffi::CString;
|
||||
use std::ffi::{CString, CStr};
|
||||
use std::mem;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub use num_rational::Rational32;
|
||||
|
||||
|
@ -28,75 +30,51 @@ use buffer::*;
|
|||
pub enum Value {
|
||||
Bool(bool),
|
||||
Int(i32),
|
||||
UInt(u32),
|
||||
Int64(i64),
|
||||
UInt64(u64),
|
||||
String(String),
|
||||
Fraction(Rational32),
|
||||
Buffer(Buffer),
|
||||
Array(Vec<Value>),
|
||||
}
|
||||
|
||||
pub trait ValueType {
|
||||
fn extract(v: &Value) -> Option<&Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_value_type(
|
||||
($t:ty, $variant:ident) => {
|
||||
impl ValueType for $t {
|
||||
fn extract(v: &Value) -> Option<&$t> {
|
||||
if let Value::$variant(ref b) = *v {
|
||||
return Some(b);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
impl_value_type!(bool, Bool);
|
||||
impl_value_type!(i32, Int);
|
||||
impl_value_type!(u32, UInt);
|
||||
impl_value_type!(i64, Int64);
|
||||
impl_value_type!(u64, UInt64);
|
||||
impl_value_type!(String, String);
|
||||
impl_value_type!(Rational32, Fraction);
|
||||
impl_value_type!(Buffer, Buffer);
|
||||
impl_value_type!(Vec<Value>, Array);
|
||||
|
||||
#[repr(C)]
|
||||
pub struct GValue {
|
||||
typ: usize,
|
||||
data: [u64; 2],
|
||||
}
|
||||
|
||||
// See gtype.h
|
||||
const TYPE_BOOLEAN: usize = (5 << 2);
|
||||
const TYPE_INT: usize = (6 << 2);
|
||||
const TYPE_STRING: usize = (16 << 2);
|
||||
|
||||
impl Value {
|
||||
pub fn to_gvalue(&self) -> GValue {
|
||||
extern "C" {
|
||||
fn g_value_init(value: *mut GValue, gtype: usize);
|
||||
fn g_value_set_boolean(value: *mut GValue, value: i32);
|
||||
fn g_value_set_int(value: *mut GValue, value: i32);
|
||||
fn g_value_set_string(value: *mut GValue, value: *const c_char);
|
||||
fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
|
||||
fn gst_fraction_get_type() -> usize;
|
||||
fn g_value_set_boxed(value: *mut GValue, boxed: *const c_void);
|
||||
fn gst_buffer_get_type() -> usize;
|
||||
fn gst_value_array_get_type() -> usize;
|
||||
fn gst_value_array_append_and_take_value(value: *mut GValue, element: *mut GValue);
|
||||
}
|
||||
|
||||
let mut gvalue: GValue = unsafe { mem::zeroed() };
|
||||
|
||||
match *self {
|
||||
Value::Bool(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
|
||||
},
|
||||
Value::Int(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
|
||||
g_value_set_int(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::String(ref v) => unsafe {
|
||||
let v_cstr = CString::new(String::from(v.clone())).unwrap();
|
||||
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
|
||||
g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
|
||||
},
|
||||
Value::Fraction(ref v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_fraction_get_type());
|
||||
gst_value_set_fraction(&mut gvalue as *mut GValue, *v.numer(), *v.denom());
|
||||
},
|
||||
Value::Buffer(ref buffer) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_buffer_get_type());
|
||||
g_value_set_boxed(&mut gvalue as *mut GValue, buffer.as_ptr());
|
||||
},
|
||||
Value::Array(ref array) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, gst_value_array_get_type());
|
||||
|
||||
for e in array {
|
||||
let mut e_value = e.to_gvalue();
|
||||
gst_value_array_append_and_take_value(&mut gvalue as *mut GValue,
|
||||
&mut e_value as *mut GValue);
|
||||
// Takes ownership, invalidate GValue
|
||||
e_value.typ = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
impl GValue {
|
||||
pub fn new() -> GValue {
|
||||
let gvalue: GValue = unsafe { mem::zeroed() };
|
||||
|
||||
gvalue
|
||||
}
|
||||
|
@ -114,6 +92,180 @@ impl Drop for GValue {
|
|||
}
|
||||
}
|
||||
|
||||
// See gtype.h
|
||||
const TYPE_BOOLEAN: usize = (5 << 2);
|
||||
const TYPE_INT: usize = (6 << 2);
|
||||
const TYPE_UINT: usize = (7 << 2);
|
||||
const TYPE_INT64: usize = (10 << 2);
|
||||
const TYPE_UINT64: usize = (11 << 2);
|
||||
const TYPE_STRING: usize = (16 << 2);
|
||||
|
||||
extern "C" {
|
||||
fn gst_buffer_get_type() -> usize;
|
||||
fn gst_fraction_get_type() -> usize;
|
||||
fn gst_value_array_get_type() -> usize;
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TYPE_BUFFER: usize = unsafe { gst_buffer_get_type() };
|
||||
static ref TYPE_FRACTION: usize = unsafe { gst_fraction_get_type() };
|
||||
static ref TYPE_GST_VALUE_ARRAY: usize = unsafe { gst_value_array_get_type() };
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn to_gvalue(&self) -> GValue {
|
||||
extern "C" {
|
||||
fn g_value_init(value: *mut GValue, gtype: usize);
|
||||
fn g_value_set_boolean(value: *mut GValue, value: i32);
|
||||
fn g_value_set_int(value: *mut GValue, value: i32);
|
||||
fn g_value_set_uint(value: *mut GValue, value: u32);
|
||||
fn g_value_set_int64(value: *mut GValue, value: i64);
|
||||
fn g_value_set_uint64(value: *mut GValue, value: u64);
|
||||
fn g_value_set_string(value: *mut GValue, value: *const c_char);
|
||||
fn gst_value_set_fraction(value: *mut GValue, value_n: i32, value_d: i32);
|
||||
fn g_value_set_boxed(value: *mut GValue, boxed: *const c_void);
|
||||
fn gst_value_array_append_and_take_value(value: *mut GValue, element: *mut GValue);
|
||||
}
|
||||
|
||||
let mut gvalue = GValue::new();
|
||||
|
||||
match *self {
|
||||
Value::Bool(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_BOOLEAN);
|
||||
g_value_set_boolean(&mut gvalue as *mut GValue, if v { 1 } else { 0 });
|
||||
},
|
||||
Value::Int(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_INT);
|
||||
g_value_set_int(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::UInt(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_UINT);
|
||||
g_value_set_uint(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::Int64(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_INT64);
|
||||
g_value_set_int64(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::UInt64(v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_UINT64);
|
||||
g_value_set_uint64(&mut gvalue as *mut GValue, v);
|
||||
},
|
||||
Value::String(ref v) => unsafe {
|
||||
let v_cstr = CString::new(String::from(v.clone())).unwrap();
|
||||
|
||||
g_value_init(&mut gvalue as *mut GValue, TYPE_STRING);
|
||||
g_value_set_string(&mut gvalue as *mut GValue, v_cstr.as_ptr());
|
||||
},
|
||||
Value::Fraction(ref v) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, *TYPE_FRACTION);
|
||||
gst_value_set_fraction(&mut gvalue as *mut GValue, *v.numer(), *v.denom());
|
||||
},
|
||||
Value::Buffer(ref buffer) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, *TYPE_BUFFER);
|
||||
g_value_set_boxed(&mut gvalue as *mut GValue, buffer.as_ptr());
|
||||
},
|
||||
Value::Array(ref array) => unsafe {
|
||||
g_value_init(&mut gvalue as *mut GValue, *TYPE_GST_VALUE_ARRAY);
|
||||
|
||||
for e in array {
|
||||
let mut e_value = e.to_gvalue();
|
||||
gst_value_array_append_and_take_value(&mut gvalue as *mut GValue,
|
||||
&mut e_value as *mut GValue);
|
||||
// Takes ownership, invalidate GValue
|
||||
e_value.typ = 0;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
gvalue
|
||||
}
|
||||
|
||||
pub fn from_gvalue(gvalue: &GValue) -> Option<Self> {
|
||||
extern "C" {
|
||||
fn g_value_get_boolean(value: *const GValue) -> i32;
|
||||
fn g_value_get_int(value: *const GValue) -> i32;
|
||||
fn g_value_get_uint(value: *const GValue) -> u32;
|
||||
fn g_value_get_int64(value: *const GValue) -> i64;
|
||||
fn g_value_get_uint64(value: *const GValue) -> u64;
|
||||
fn g_value_get_string(value: *const GValue) -> *const c_char;
|
||||
fn gst_value_get_fraction_numerator(value: *const GValue) -> i32;
|
||||
fn gst_value_get_fraction_denominator(value: *const GValue) -> i32;
|
||||
fn g_value_get_boxed(value: *const GValue) -> *mut c_void;
|
||||
fn gst_value_array_get_size(value: *const GValue) -> u32;
|
||||
fn gst_value_array_get_value(value: *const GValue, index: u32) -> *const GValue;
|
||||
}
|
||||
|
||||
match gvalue.typ {
|
||||
TYPE_BOOLEAN => unsafe {
|
||||
Some(Value::Bool(if g_value_get_boolean(gvalue as *const GValue) == 0 {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}))
|
||||
},
|
||||
TYPE_INT => unsafe { Some(Value::Int(g_value_get_int(gvalue as *const GValue))) },
|
||||
TYPE_UINT => unsafe { Some(Value::UInt(g_value_get_uint(gvalue as *const GValue))) },
|
||||
TYPE_INT64 => unsafe { Some(Value::Int64(g_value_get_int64(gvalue as *const GValue))) },
|
||||
TYPE_UINT64 => unsafe {
|
||||
Some(Value::UInt64(g_value_get_uint64(gvalue as *const GValue)))
|
||||
},
|
||||
TYPE_STRING => unsafe {
|
||||
let s = g_value_get_string(gvalue as *const GValue);
|
||||
if s.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let cstr = CStr::from_ptr(s);
|
||||
match cstr.to_str() {
|
||||
Err(_) => None,
|
||||
Ok(s) => Some(Value::String(s.into())),
|
||||
}
|
||||
},
|
||||
typ if typ == *TYPE_FRACTION => unsafe {
|
||||
let n = gst_value_get_fraction_numerator(gvalue as *const GValue);
|
||||
let d = gst_value_get_fraction_denominator(gvalue as *const GValue);
|
||||
|
||||
Some(Value::Fraction(Rational32::new(n, d)))
|
||||
},
|
||||
typ if typ == *TYPE_BUFFER => unsafe {
|
||||
let b = g_value_get_boxed(gvalue as *const GValue);
|
||||
|
||||
if b.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Value::Buffer(Buffer::new_from_ptr(b)))
|
||||
},
|
||||
typ if typ == *TYPE_GST_VALUE_ARRAY => unsafe {
|
||||
let n = gst_value_array_get_size(gvalue as *const GValue);
|
||||
|
||||
let mut vec = Vec::with_capacity(n as usize);
|
||||
|
||||
for i in 0..n {
|
||||
let val = gst_value_array_get_value(gvalue as *const GValue, i);
|
||||
|
||||
if val.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(val) = Value::from_gvalue(&*val) {
|
||||
vec.push(val);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
Some(Value::Array(vec))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get<T: ValueType>(&self) -> Option<&T> {
|
||||
T::extract(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Value {
|
||||
fn from(f: bool) -> Value {
|
||||
Value::Bool(f)
|
||||
|
@ -126,6 +278,24 @@ impl From<i32> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Value {
|
||||
fn from(f: u32) -> Value {
|
||||
Value::UInt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Value {
|
||||
fn from(f: i64) -> Value {
|
||||
Value::Int64(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Value {
|
||||
fn from(f: u64) -> Value {
|
||||
Value::UInt64(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(f: String) -> Value {
|
||||
Value::String(f)
|
||||
|
@ -173,3 +343,83 @@ impl<'a> From<&'a [Value]> for Value {
|
|||
Value::Array(f.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct TypedValue<T>
|
||||
where T: ValueType
|
||||
{
|
||||
value: Value,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> TypedValue<T>
|
||||
where T: ValueType
|
||||
{
|
||||
pub fn new(value: Value) -> Self {
|
||||
TypedValue {
|
||||
value: value,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> Value {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for TypedValue<T>
|
||||
where T: ValueType
|
||||
{
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
self.value.try_get().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for TypedValue<T>
|
||||
where T: ValueType
|
||||
{
|
||||
fn as_ref(&self) -> &T {
|
||||
self.value.try_get().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct TypedValueRef<'a, T>
|
||||
where T: ValueType
|
||||
{
|
||||
value: &'a Value,
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> TypedValueRef<'a, T>
|
||||
where T: ValueType
|
||||
{
|
||||
pub fn new(value: &'a Value) -> TypedValueRef<'a, T> {
|
||||
TypedValueRef {
|
||||
value: value,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value(self) -> &'a Value {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for TypedValueRef<'a, T>
|
||||
where T: ValueType
|
||||
{
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
self.value.try_get().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> AsRef<T> for TypedValueRef<'a, T>
|
||||
where T: ValueType
|
||||
{
|
||||
fn as_ref(&self) -> &T {
|
||||
self.value.try_get().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue