require "./serializable"
def Object.fromRsconf(toplevel : ::RemiLib::RSConf::RSValue)
new(toplevel)
end
def Object.fromRsconf(data : String|IO|Path)
parsed = ::RemiLib::RSConf::Parser.parse(data)
new(parsed)
end
def Array.fromRsconf(toplevel : ::RemiLib::RSConf::RSValue, &) : Nil
unless toplevel.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Toplevel is not an array.")
end
new(toplevel) do |element|
yield element
end
nil
end
def Array.fromRsconf(toplevel : String|IO|Path, &) : Nil
toplevel = ::RemiLib::RSConf::Parser.parse(toplevel)
unless toplevel.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Toplevel is not an array.")
end
new(toplevel) do |element|
yield element
end
nil
end
def Deque.fromRsconf(toplevel : ::RemiLib::RSConf::RSValue, &) : Nil
unless toplevel.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Toplevel is not an array.")
end
new(toplevel) do |element|
yield element
end
nil
end
def Deque.fromRsconf(toplevel : String|IO|Path, &) : Nil
toplevel = ::RemiLib::RSConf::Parser.parse(toplevel)
unless toplevel.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Toplevel is not an array.")
end
new(toplevel) do |element|
yield element
end
nil
end
def Nil.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSValue)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
unless val.isNil?
raise ::RemiLib::RSConf::RSConfError.new("Not a null value")
end
Nil.new
end
def Bool.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSValue)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
unless val.is_a?(::RemiLib::RSConf::RSScalar) && val.isBool?
raise ::RemiLib::RSConf::RSConfError.new("Not a null value")
end
val.bool
end
{% for type, method in {
"Int8" => "i8",
"Int16" => "i16",
"Int32" => "i32",
"Int64" => "i64",
"Int128" => "i128",
"UInt8" => "u8",
"UInt16" => "u16",
"UInt32" => "u32",
"UInt64" => "u64",
"UInt128" => "u128",
} %}
def {{type.id}}.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
value = if val.isInt?
val.int
elsif val.isFloat?
val.float
else
raise ::RemiLib::RSConf::RSConfError.new("Not an integer value or a value convertable to integer")
end
begin
value.to_{{method.id}}
rescue ex : OverflowError | ArgumentError
raise ::RemiLib::RSConf::RSConfError.new("Can't read {{type.id}}")
end
end
{% end %}
def Float32.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
value = if val.isInt?
val.int
elsif val.isFloat?
val.float
else
raise ::RemiLib::RSConf::RSConfError.new("Not an integer value or a value convertable to integer")
end
begin
value.to_f32
rescue ex : OverflowError | ArgumentError
raise ::RemiLib::RSConf::RSConfError.new("Can't read Float32")
end
end
def Float64.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
value = if val.isInt?
val.int
elsif val.isFloat?
val.float
else
raise ::RemiLib::RSConf::RSConfError.new("Not an integer value or a value convertable to integer")
end
begin
value.to_f64
rescue ex : OverflowError | ArgumentError
raise ::RemiLib::RSConf::RSConfError.new("Can't read Float64")
end
end
def String.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
if val.isString?
val.string
else
raise ::RemiLib::RSConf::RSConfError.new("Not a string")
end
end
def Path.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
if val.isString?
new(val.string)
else
raise ::RemiLib::RSConf::RSConfError.new("Not a string")
end
end
def Array.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
ret = new
new(val) do |element|
ret << element
end
ret
end
def Array.new(val : ::RemiLib::RSConf::RSValue, &)
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
val.each do |elt|
yield T.new(elt)
end
end
def Deque.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
ret = new
new(val) do |element|
ret << element
end
ret
end
def Deque.new(val : ::RemiLib::RSConf::RSValue, &)
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
val.each do |elt|
yield T.new(elt)
end
end
def Set.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
ret = new
val.each do |elt|
ret << T.new(elt)
end
ret
end
def Hash.new(value : ::RemiLib::RSConf::RSValue)
unless value.is_a?(::RemiLib::RSConf::RSObject)
raise ::RemiLib::RSConf::RSConfError.new("Not an object")
end
ret = new
value.each do |key, val|
ret[key] = V.new(val)
end
ret
end
def Tuple.new(val : ::RemiLib::RSConf::RSValue)
{% begin %}
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
value = Tuple.new(
{% for i in 0...T.size %}
(self[{{i}}].new(val[i])),
{% end %}
)
value
{% end %}
end
def NamedTuple.new(val : ::RemiLib::RSConf::RSValue)
{% begin %}
{% for key, type in T %}
{% if type.nilable? %}
%var{key.id} = nil
{% else %}
%var{key.id} = uninitialized typeof(element_type({{ key.symbolize }}))
%found{key.id} = false
{% end %}
{% end %}
unless val.is_a?(::RemiLib::RSConf::RSObject)
raise ::RemiLib::RSConf::RSConfError.new("Not an object")
end
val.each do |key, val|
case key
{% for key, type in T %}
when {{key.stringify}}
%var{key.id} = self[{{ key.symbolize }}].new(val)
{% unless type.nilable? %}
%found{key.id} = true
{% end %}
{% end %}
end
end
{% for key, type in T %}
{% unless type.nilable? %}
unless %found{key.id}
raise ::RemiLib::RSConf::RSConfError.new("Missing RSConf attribute: #{ {{ key.id.stringify }} }")
end
{% end %}
{% end %}
NamedTuple.new(
{% for key in T.keys %}
{{ key.id.stringify }}: %var{key.id},
{% end %}
)
{% end %}
end
def Enum.new(val : ::RemiLib::RSConf::RSValue)
{% if @type.annotation(Flags) %}
unless val.is_a?(::RemiLib::RSConf::RSArray)
raise ::RemiLib::RSConf::RSConfError.new("Not an array")
end
value = {{ @type }}::None
val.each do |elt|
if elt.isString?
string = elt.string
value |= parse?(string) || raise ::RemiLib::RSConf::RSConfError.new("Unknown enum #{self} value: #{string.inspect}")
else
raise ::RemiLib::RSConf::RSConfError.new("Not a string, cannot convert to enum #{self} value")
end
end
value
{% else %}
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
if val.isString?
string = val.string
parse?(string) || raise ::RemiLib::RSConf::RSConfError.new("Unknown enum #{self} value: #{string.inspect}")
else
raise ::RemiLib::RSConf::RSConfError.new("Not a string, cannot convert to enum #{self} value")
end
{% end %}
end
module Enum::ValueConverter(T)
def self.new(val : ::RemiLib::RSConf::RSValue) : T
from_json(val)
end
def self.from_json(val : ::RemiLib::RSConf::RSValue) : T
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfError.new("Not a scalar")
end
if val.isInt?
T.from_value?(val.int) || raise RSConfError.new("Unknown enum #{T} value: #{val.int}")
else
raise RSConfError.new("Cannot convert to enum #{T}, not an integer")
end
end
end
def Union.new(val : ::RemiLib::RSConf::RSValue)
{% begin %}
case
{% if T.includes? Nil %}
when val.is_a?(::RemiLib::RSConf::RSScalar) && val.isNil?
return nil
{% end %}
{% if T.includes? Bool %}
when val.is_a?(::RemiLib::RSConf::RSScalar) && val.isBool?
return val.bool
{% end %}
{% if T.includes? String %}
when val.is_a?(::RemiLib::RSConf::RSScalar) && val.isString?
return val.string
{% end %}
when val.is_a?(::RemiLib::RSConf::RSScalar) && val.isInt?
{% for type, method in {
Int128 => "i128",
UInt128 => "u128",
Int64 => "i64",
UInt64 => "u64",
Int32 => "i32",
UInt32 => "u32",
Int16 => "i16",
UInt16 => "u16",
Int8 => "i8",
UInt8 => "u8"
} %}
{% if T.includes?(type) %}
value = val.tryInt
return value.to_{{method.id}} unless value.nil?
{% end %}
{% end %}
when val.is_a?(::RemiLib::RSConf::RSScalar) && val.isFloat?
{% if T.includes?(Float64) %}
value = val.tryFloat
return value.to_f64 unless value.nil?
{% elsif T.includes?(Float32) %}
value = val.tryFloat
return value.to_f64 unless value.nil?
{% end %}
else
# no priority type
end
{% end %}
{% begin %}
{% primitive_types = [Nil, Bool, String] + Number::Primitive.union_types %}
{% non_primitives = T.reject { |t| primitive_types.includes? t } %}
# If after traversing all the types we are left with just one
# non-primitive type, we can parse it directly
{% if non_primitives.size == 1 %}
return {{non_primitives[0]}}.new(val)
{% else %}
{% for type in non_primitives %}
begin
return {{type}}.fromRsconf(val)
rescue ::RemiLib::RSConf::RSConfError
# Ignore
end
{% end %}
raise ::RemiLib::RSConf::RSConfError.new("Couldn't parse #{self} from RSConf value")
{% end %}
{% end %}
end
def Time.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfParseError.new("Not a scalar")
end
unless val.string?
raise ::RemiLib::RSConf::RSConfParseError.new("Not a string")
end
Time::Format::ISO_8601_DATE_TIME.parse(val.string)
end
def Time::Location.new(val : ::RemiLib::RSConf::RSValue)
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfParseError.new("Not a scalar")
end
unless val.string?
raise ::RemiLib::RSConf::RSConfParseError.new("Not a string")
end
load(val.string)
end
struct Time::Format
def fromRsconf(val : ::RemiLib::RSConf::RSValue) : Time
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfParseError.new("Not a scalar")
end
unless val.string?
raise ::RemiLib::RSConf::RSConfParseError.new("Not a string")
end
parse(val.string, Time::Location::UTC)
end
end
module Time::EpochConverter
def self.fromRsconf(val : ::RemiLib::RSConf::RSValue) : Time
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfParseError.new("Not a scalar")
end
unless val.isInt?
raise ::RemiLib::RSConf::RSConfParseError.new("Not an integer")
end
Time.unix(val.int)
end
end
module Time::EpochMillisConverter
def self.fromRsconf(val : ::RemiLib::RSConf::RSValue) : Time
unless val.is_a?(::RemiLib::RSConf::RSScalar)
raise ::RemiLib::RSConf::RSConfParseError.new("Not a scalar")
end
unless val.isInt?
raise ::RemiLib::RSConf::RSConfParseError.new("Not an integer")
end
Time.unix_ms(val.int)
end
end