blob: cd7e4f44c4433e578774041e337752741cb9aad6 [file] [log] [blame]
/**
* Copyright (C) 2012 ciere consulting, ciere.com
* Copyright (C) 2012 Jeroen Habraken
* Copyright (c) 2011 Joel de Guzman
* Copyright (C) 2011, 2012 Object Modeling Designs
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef CIERE_JSON_VALUE_IMPL_HPP
#define CIERE_JSON_VALUE_IMPL_HPP
#include <iostream> //test
#include "../value.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/assert.hpp>
namespace ciere { namespace json
{
namespace detail
{
template< typename T >
struct extract
{
template<typename A>
static T get(A & v) { return boost::get<T>(v); }
template<typename A>
static const T get(const A & v) { return boost::get<T>(v); }
};
template<typename R>
struct convert
{
BOOST_MPL_ASSERT_MSG(
!(boost::is_same<R,null_t>::value)
, CANNOT_GET_AS_WITH_NULL_T
, (R)
);
template<typename T>
static R apply( T const & v
, typename boost::enable_if<boost::is_convertible<R,T> >::type* dummy=0 )
{
return v;
}
static R apply( string_t const & v )
{
return boost::lexical_cast<R>(v);
}
template<typename T>
static R apply( T const & v
, typename boost::disable_if<boost::is_convertible<R,T> >::type* dummy=0 )
{
throw get_as_error();
return R();
}
};
template<>
struct convert<string_t>
{
static string_t apply( string_t const & v)
{
return v;
}
static string_t apply( float_t const & v )
{
return boost::lexical_cast<std::string>(v);
}
static string_t apply( int_t const & v )
{
return boost::lexical_cast<std::string>(v);
}
static string_t apply( bool_t const & v)
{
return (v ? "true" : "false");
}
static string_t apply( null_t const & )
{
return "null";
}
template<typename T>
static string_t apply( T const & v )
{
throw get_as_error();
return "";
}
};
template<>
struct convert<bool_t>
{
template<typename T>
static bool_t apply( T const & v
, typename boost::enable_if<boost::is_convertible<bool_t,T> >::type* dummy=0 )
{
return v;
}
static bool_t apply( string_t const & v )
{
if( v == "true" ) return true;
else return false;
}
template<typename T>
static bool_t apply( T const & v
, typename boost::disable_if<boost::is_convertible<bool_t,T> >::type* dummy=0 )
{
throw get_as_error();
return false;
}
};
template<typename T>
struct convert_to : public boost::static_visitor<T>
{
template<typename V>
T operator()(V const & v) const
{
try
{
return convert<T>::apply(v);
}
catch(...)
{
throw get_as_error();
}
}
// if the types are the same, no conversion required
T operator()(T const & v) const
{
return v;
}
};
}
struct value::make_json_value
{
json::value& operator()(json::value& v) const { return v; }
const json::value& operator()(const json::value& v) const { return v; }
};
struct value::make_json_member
{
value::member operator()(object_t::value_type & v) const { return value::member(v); }
value::const_member operator()(const object_t::value_type & v) const { return value::const_member(v); }
};
// -------------------------------------------------------------------------------
// array handling
// -------------------------------------------------------------------------------
/**
* Add compatible type to the end of the array
*/
template< typename T >
value& value::add( T v )
{
push_back(v);
return *this;
}
/**
* Add a compatible type to the end of the array, functor style.
*/
template< typename T >
value& value::operator()( T v )
{
return add(v);
}
/**
* Add compatible type to the end of the array, stl style-ish
* Actually returns a reference the newly added value.
*/
template< typename T >
value& value::push_back( T v )
{
array_t* p_array = boost::get<array_t>(&base_type::get());
// if we aren't an array, we need to be an array
if( !p_array )
{
base_type::get() = array_t();
p_array = boost::get<array_t>(&base_type::get());
}
p_array->push_back( (json::value(v)) );
return p_array->back();
}
// -------------------------------------------------------------------------------
// object handling
// -------------------------------------------------------------------------------
template< typename T >
value& value::set( string_t const & name, T v )
{
object_t* p_object = boost::get<object_t>(&base_type::get());
// if this isn't an object type ... it needs to be
if( !p_object )
{
base_type::get() = object_t();
p_object = boost::get<object_t>(&base_type::get());
}
(*p_object)[name] = v;
return *this;
}
template< typename T >
value& value::operator()( string_t const & name, T v )
{
return set(name,v);
}
// -------------------------------------------------------------------------------
// Extract based on type
// -------------------------------------------------------------------------------
template< typename T >
T value::get()
{
return detail::extract<T>::get(base_type::get());
}
template< typename T >
const T value::get() const
{
return detail::extract<T>::get(base_type::get());
}
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
// Extract based on type and convert to requested type
// -------------------------------------------------------------------------------
template< typename T >
T value::get_as()
{
return boost::apply_visitor(detail::convert_to<T>(),base_type::get());
}
template< typename T >
const T value::get_as() const
{
return boost::apply_visitor(detail::convert_to<T>(),base_type::get());
}
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
}}
#endif // CIERE_JSON_VALUE_IMPL_HPP