<commit_before>// Copyright 2016 Frog Chen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=============================================================================
// ■ global.cpp
//-----------------------------------------------------------------------------
//   全局包含脖子文件。系统已经去掉了头，可以安全食用了。
//=============================================================================

namespace Global {
	//-------------------------------------------------------------------------
	// ● 定义
	//-------------------------------------------------------------------------
	// 因为没有头，所以只能这样定义uint*_t了。
	typedef __UINT8_TYPE__ uint8_t;
	typedef __UINT16_TYPE__ uint16_t;
	typedef __UINT32_TYPE__ uint32_t;
	typedef __UINT64_TYPE__ uint64_t;

	// 看上去是另一种类型，但其实就是无符号的整数
	typedef uint32_t type_address;
	typedef uint32_t type_size;
	typedef uint16_t type_port;

	// 通用的数据类型
	struct pos {
		int x;
		int y;
	};
	struct vector {
		int x;
		int y;
	};
	struct rect {
		int x;
		int y;
		int width;
		int height;
	};
}

using namespace Global;
<commit_msg>添加数据类型size<commit_after>// Copyright 2016 Frog Chen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=============================================================================
// ■ global.cpp
//-----------------------------------------------------------------------------
//   全局包含脖子文件。系统已经去掉了头，可以安全食用了。
//=============================================================================

namespace Global {
	//-------------------------------------------------------------------------
	// ● 定义
	//-------------------------------------------------------------------------
	// 因为没有头，所以只能这样定义uint*_t了。
	typedef __UINT8_TYPE__ uint8_t;
	typedef __UINT16_TYPE__ uint16_t;
	typedef __UINT32_TYPE__ uint32_t;
	typedef __UINT64_TYPE__ uint64_t;

	// 看上去是另一种类型，但其实就是无符号的整数
	typedef uint32_t type_address;
	typedef uint32_t type_size;
	typedef uint16_t type_port;

	// 通用的数据类型
	struct pos {
		int x;
		int y;
	};
	struct vector {
		int x;
		int y;
	};
	struct size {
		int width;
		int height;
	};
	struct rect {
		int x;
		int y;
		int width;
		int height;
	};
}

using namespace Global;
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Endless Mobile
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * Written by:
 *     Jasper St. Pierre <jstpierre@mecheye.net>
 */

#include "gobject.h"

#include "function.h"
#include "value.h"
#include "closure.h"

using namespace v8;

namespace GNodeJS {

static bool InitGParameterFromProperty(GParameter    *parameter,
                                       void          *klass,
                                       Handle<String> name,
                                       Handle<Value>  value)
{
    String::Utf8Value name_str (name);
    GParamSpec *pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), *name_str);
    if (pspec == NULL)
        return false;

    parameter->name = pspec->name;
    g_value_init (&parameter->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
    V8ToGValue (&parameter->value, value);
    return true;
}

static bool InitGParametersFromProperty(GParameter    **parameters_p,
                                        int            *n_parameters_p,
                                        void           *klass,
                                        Handle<Object>  property_hash)
{
    Local<Array> properties = property_hash->GetOwnPropertyNames ();
    int n_parameters = properties->Length();
    GParameter *parameters = g_new0 (GParameter, n_parameters);

    for (int i = 0; i < n_parameters; i++) {
        Local<Value> name = properties->Get (i);
        Local<Value> value = property_hash->Get (name);

        if (!InitGParameterFromProperty (&parameters[i], klass, name->ToString (), value))
            return false;
    }

    *parameters_p = parameters;
    *n_parameters_p = n_parameters;
    return true;
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down);

G_DEFINE_QUARK(gnode_js_object, gnode_js_object);

static void AssociateGObject(Isolate *isolate, Handle<Object> object, GObject *gobject) {
    object->SetAlignedPointerInInternalField (0, gobject);

    g_object_ref_sink (gobject);
    g_object_add_toggle_ref (gobject, ToggleNotify, NULL);

    Persistent<Object> *persistent = new Persistent<Object>(isolate, object);
    g_object_set_qdata (gobject, gnode_js_object_quark (), persistent);
}

static void GObjectConstructor(const FunctionCallbackInfo<Value> &args) {
    Isolate *isolate = args.GetIsolate ();

    /* The flow of this function is a bit twisty.

     * There's two cases for when this code is called:
     * user code doing `new Gtk.Widget({ ... })`, and
     * internal code as part of WrapperFromGObject, where
     * the constructor is called with one external. */

    if (!args.IsConstructCall ()) {
        isolate->ThrowException (Exception::TypeError (String::NewFromUtf8 (isolate, "Not a construct call.")));
        return;
    }

    Handle<Object> self = args.This ();

    if (args[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromGObject is called. */

        void *data = External::Cast (*args[0])->Value ();
        GObject *gobject = G_OBJECT (data);

        AssociateGObject (isolate, self, gobject);
    } else {
        /* User code calling `new Gtk.Widget({ ... })` */

        GObject *gobject;
        GIBaseInfo *info = (GIBaseInfo *) External::Cast (*args.Data ())->Value ();
        GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
        void *klass = g_type_class_ref (gtype);

        GParameter *parameters = NULL;
        int n_parameters = 0;

        if (args[0]->IsObject ()) {
            Local<Object> property_hash = args[0]->ToObject ();

            if (!InitGParametersFromProperty (&parameters, &n_parameters, klass, property_hash)) {
                isolate->ThrowException (Exception::TypeError (String::NewFromUtf8 (isolate, "Unable to make GParameters.")));
                goto out;
            }
        }

        gobject = (GObject *) g_object_newv (gtype, n_parameters, parameters);
        AssociateGObject (isolate, self, gobject);

    out:
        g_free (parameters);
        g_type_class_unref (klass);
    }
}

G_DEFINE_QUARK(gnode_js_template, gnode_js_template);

static void DefineConstructorMethods(Isolate *isolate, Handle<FunctionTemplate> constructor, GIBaseInfo *info) {
    int n_methods = g_object_info_get_n_methods (info);
    for (int i = 0; i < n_methods; i++) {
        GIFunctionInfo *meth_info = g_object_info_get_method (info, i);
        GIFunctionInfoFlags flags = g_function_info_get_flags (meth_info);

        if (!(flags & GI_FUNCTION_IS_METHOD)) {
            const char *function_name = g_base_info_get_name ((GIBaseInfo *) meth_info);
            Handle<Function> fn = MakeFunction (isolate, meth_info);
            constructor->Set (String::NewFromUtf8 (isolate, function_name), fn);
        }

        g_base_info_unref ((GIBaseInfo *) meth_info);
    }
}

static void DefinePrototypeMethods(Isolate *isolate, Handle<ObjectTemplate> prototype, GIBaseInfo *info) {
    int n_methods = g_object_info_get_n_methods (info);
    for (int i = 0; i < n_methods; i++) {
        GIFunctionInfo *meth_info = g_object_info_get_method (info, i);
        GIFunctionInfoFlags flags = g_function_info_get_flags (meth_info);

        if (flags & GI_FUNCTION_IS_METHOD) {
            const char *function_name = g_base_info_get_name ((GIBaseInfo *) meth_info);
            Handle<Function> fn = MakeFunction (isolate, meth_info);
            prototype->Set (String::NewFromUtf8 (isolate, function_name), fn);
        }

        g_base_info_unref ((GIBaseInfo *) meth_info);
    }
}

static void SignalConnectInternal(const FunctionCallbackInfo<Value> &args, bool after) {
    Isolate *isolate = args.GetIsolate ();
    GObject *gobject = GObjectFromWrapper (args.This ());

    String::Utf8Value signal_name (args[0]->ToString ());
    Handle<Function> callback = Local<Function>::Cast (args[1]->ToObject ());
    GClosure *gclosure = MakeClosure (isolate, callback);

    ulong handler_id = g_signal_connect_closure (gobject, *signal_name, gclosure, after);
    args.GetReturnValue ().Set(Integer::NewFromUnsigned (isolate, handler_id));
}

static void SignalConnect(const FunctionCallbackInfo<Value> &args) {
    SignalConnectInternal (args, false);
}

static Handle<FunctionTemplate> GetBaseClassTemplate(Isolate *isolate) {
    Local<FunctionTemplate> tpl = FunctionTemplate::New (isolate);
    Handle<ObjectTemplate> proto = tpl->PrototypeTemplate ();
    proto->Set (String::NewFromUtf8 (isolate, "connect"), FunctionTemplate::New (isolate, SignalConnect)->GetFunction ());
    return tpl;
}

static Handle<FunctionTemplate> GetClassTemplateFromGI(Isolate *isolate, GIBaseInfo *info);

static void ClassDestroyed(const WeakCallbackData<FunctionTemplate, GIBaseInfo> &data) {
    GIBaseInfo *info = data.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    void *type_data = g_type_get_qdata (gtype, gnode_js_template_quark ());
    assert (type_data != NULL);
    Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) type_data;
    delete persistent;

    g_type_set_qdata (gtype, gnode_js_template_quark (), NULL);
    g_base_info_unref (info);
}

static Handle<FunctionTemplate> GetClassTemplate(Isolate *isolate, GIBaseInfo *info, GType gtype) {
    void *data = g_type_get_qdata (gtype, gnode_js_template_quark ());

    if (data) {
        Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) data;
        Handle<FunctionTemplate> tpl = Handle<FunctionTemplate>::New (isolate, *persistent);
        return tpl;
    } else {
        Handle<FunctionTemplate> tpl = FunctionTemplate::New (isolate, GObjectConstructor, External::New (isolate, info));

        Persistent<FunctionTemplate> *persistent = new Persistent<FunctionTemplate>(isolate, tpl);
        persistent->SetWeak (g_base_info_ref (info), ClassDestroyed);
        g_type_set_qdata (gtype, gnode_js_template_quark (), persistent);

        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (String::NewFromUtf8 (isolate, class_name));

        tpl->InstanceTemplate ()->SetInternalFieldCount (1);

        DefineConstructorMethods (isolate, tpl, info);
        DefinePrototypeMethods (isolate, tpl->PrototypeTemplate (), info);

        GIObjectInfo *parent_info = g_object_info_get_parent (info);
        if (parent_info) {
            Handle<FunctionTemplate> parent_tpl = GetClassTemplateFromGI (isolate, (GIBaseInfo *) parent_info);
            tpl->Inherit (parent_tpl);
        } else {
            tpl->Inherit (GetBaseClassTemplate (isolate));
        }

        return tpl;
    }
}

static Handle<FunctionTemplate> GetClassTemplateFromGI(Isolate *isolate, GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
    return GetClassTemplate (isolate, info, gtype);
}

static Handle<FunctionTemplate> GetClassTemplateFromGType(Isolate *isolate, GType gtype) {
    GIRepository *repo = g_irepository_get_default ();
    GIBaseInfo *info = g_irepository_find_by_gtype (repo, gtype);
    return GetClassTemplate (isolate, info, gtype);
}

Handle<Function> MakeClass(Isolate *isolate, GIBaseInfo *info) {
    Handle<FunctionTemplate> tpl = GetClassTemplateFromGI (isolate, info);
    return tpl->GetFunction ();
}

static void ObjectDestroyed(const WeakCallbackData<Object, GObject> &data) {
    GObject *gobject = data.GetParameter ();

    void *type_data = g_object_get_qdata (gobject, gnode_js_object_quark ());
    assert (type_data != NULL);
    Persistent<Object> *persistent = (Persistent<Object> *) type_data;
    delete persistent;

    /* We're destroying the wrapper object, so make sure to clear out
     * the qdata that points back to us. */
    g_object_set_qdata (gobject, gnode_js_object_quark (), NULL);

    g_object_unref (gobject);
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down) {
    void *data = g_object_get_qdata (gobject, gnode_js_object_quark ());
    assert (data != NULL);

    Persistent<Object> *persistent = (Persistent<Object> *) data;

    if (toggle_down) {
        /* We're dropping from 2 refs to 1 ref. We are the last holder. Make
         * sure that that our weak ref is installed. */
        persistent->SetWeak (gobject, ObjectDestroyed);
    } else {
        /* We're going from 1 ref to 2 refs. We can't let our wrapper be
         * collected, so make sure that our reference is persistent */
        persistent->ClearWeak ();
    }
}

Handle<Value> WrapperFromGObject(Isolate *isolate, GObject *gobject) {
    void *data = g_object_get_qdata (gobject, gnode_js_object_quark ());

    if (data) {
        /* Easy case: we already have an object. */
        Persistent<Object> *persistent = (Persistent<Object> *) data;
        Handle<Object> obj = Handle<Object>::New (isolate, *persistent);
        return obj;
    } else {
        GType gtype = G_OBJECT_TYPE (gobject);

        Handle<FunctionTemplate> tpl = GetClassTemplateFromGType (isolate, gtype);
        Handle<Function> constructor = tpl->GetFunction ();

        Handle<Value> gobject_external = External::New (isolate, gobject);
        Handle<Value> args[] = { gobject_external };
        Handle<Object> obj = constructor->NewInstance (1, args);
        return obj;
    }
}

GObject * GObjectFromWrapper(Handle<Value> value) {
    Handle<Object> object = value->ToObject ();
    void *data = object->GetAlignedPointerFromInternalField (0);
    GObject *gobject = G_OBJECT (data);
    return gobject;
}

};
<commit_msg>gobject: Implement read support for GObject properties<commit_after>/*
 * Copyright (C) 2014 Endless Mobile
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * Written by:
 *     Jasper St. Pierre <jstpierre@mecheye.net>
 */

#include "gobject.h"

#include "function.h"
#include "value.h"
#include "closure.h"

using namespace v8;

namespace GNodeJS {

static bool InitGParameterFromProperty(GParameter    *parameter,
                                       void          *klass,
                                       Handle<String> name,
                                       Handle<Value>  value)
{
    String::Utf8Value name_str (name);
    GParamSpec *pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), *name_str);
    if (pspec == NULL)
        return false;

    parameter->name = pspec->name;
    g_value_init (&parameter->value, G_PARAM_SPEC_VALUE_TYPE (pspec));
    V8ToGValue (&parameter->value, value);
    return true;
}

static bool InitGParametersFromProperty(GParameter    **parameters_p,
                                        int            *n_parameters_p,
                                        void           *klass,
                                        Handle<Object>  property_hash)
{
    Local<Array> properties = property_hash->GetOwnPropertyNames ();
    int n_parameters = properties->Length();
    GParameter *parameters = g_new0 (GParameter, n_parameters);

    for (int i = 0; i < n_parameters; i++) {
        Local<Value> name = properties->Get (i);
        Local<Value> value = property_hash->Get (name);

        if (!InitGParameterFromProperty (&parameters[i], klass, name->ToString (), value))
            return false;
    }

    *parameters_p = parameters;
    *n_parameters_p = n_parameters;
    return true;
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down);

G_DEFINE_QUARK(gnode_js_object, gnode_js_object);

static void AssociateGObject(Isolate *isolate, Handle<Object> object, GObject *gobject) {
    object->SetAlignedPointerInInternalField (0, gobject);

    g_object_ref_sink (gobject);
    g_object_add_toggle_ref (gobject, ToggleNotify, NULL);

    Persistent<Object> *persistent = new Persistent<Object>(isolate, object);
    g_object_set_qdata (gobject, gnode_js_object_quark (), persistent);
}

static void GObjectConstructor(const FunctionCallbackInfo<Value> &args) {
    Isolate *isolate = args.GetIsolate ();

    /* The flow of this function is a bit twisty.

     * There's two cases for when this code is called:
     * user code doing `new Gtk.Widget({ ... })`, and
     * internal code as part of WrapperFromGObject, where
     * the constructor is called with one external. */

    if (!args.IsConstructCall ()) {
        isolate->ThrowException (Exception::TypeError (String::NewFromUtf8 (isolate, "Not a construct call.")));
        return;
    }

    Handle<Object> self = args.This ();

    if (args[0]->IsExternal ()) {
        /* The External case. This is how WrapperFromGObject is called. */

        void *data = External::Cast (*args[0])->Value ();
        GObject *gobject = G_OBJECT (data);

        AssociateGObject (isolate, self, gobject);
    } else {
        /* User code calling `new Gtk.Widget({ ... })` */

        GObject *gobject;
        GIBaseInfo *info = (GIBaseInfo *) External::Cast (*args.Data ())->Value ();
        GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
        void *klass = g_type_class_ref (gtype);

        GParameter *parameters = NULL;
        int n_parameters = 0;

        if (args[0]->IsObject ()) {
            Local<Object> property_hash = args[0]->ToObject ();

            if (!InitGParametersFromProperty (&parameters, &n_parameters, klass, property_hash)) {
                isolate->ThrowException (Exception::TypeError (String::NewFromUtf8 (isolate, "Unable to make GParameters.")));
                goto out;
            }
        }

        gobject = (GObject *) g_object_newv (gtype, n_parameters, parameters);
        AssociateGObject (isolate, self, gobject);

    out:
        g_free (parameters);
        g_type_class_unref (klass);
    }
}

G_DEFINE_QUARK(gnode_js_template, gnode_js_template);

static void DefineConstructorMethods(Isolate *isolate, Handle<FunctionTemplate> constructor, GIBaseInfo *info) {
    int n_methods = g_object_info_get_n_methods (info);
    for (int i = 0; i < n_methods; i++) {
        GIFunctionInfo *meth_info = g_object_info_get_method (info, i);
        GIFunctionInfoFlags flags = g_function_info_get_flags (meth_info);

        if (!(flags & GI_FUNCTION_IS_METHOD)) {
            const char *function_name = g_base_info_get_name ((GIBaseInfo *) meth_info);
            Handle<Function> fn = MakeFunction (isolate, meth_info);
            constructor->Set (String::NewFromUtf8 (isolate, function_name), fn);
        }

        g_base_info_unref ((GIBaseInfo *) meth_info);
    }
}

static void DefinePrototypeMethods(Isolate *isolate, Handle<ObjectTemplate> prototype, GIBaseInfo *info) {
    int n_methods = g_object_info_get_n_methods (info);
    for (int i = 0; i < n_methods; i++) {
        GIFunctionInfo *meth_info = g_object_info_get_method (info, i);
        GIFunctionInfoFlags flags = g_function_info_get_flags (meth_info);

        if (flags & GI_FUNCTION_IS_METHOD) {
            const char *function_name = g_base_info_get_name ((GIBaseInfo *) meth_info);
            Handle<Function> fn = MakeFunction (isolate, meth_info);
            prototype->Set (String::NewFromUtf8 (isolate, function_name), fn);
        }

        g_base_info_unref ((GIBaseInfo *) meth_info);
    }
}

static void ObjectPropertyGetter(Local<String> name,
                                 const PropertyCallbackInfo<Value> &info)
{
    Isolate *isolate = info.GetIsolate ();
    GObject *gobject = GObjectFromWrapper (info.This ());
    String::Utf8Value name_v (name);
    const char *prop_name = *name_v;

    GParamSpec *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (gobject), prop_name);
    GValue value = {};
    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));

    g_object_get_property (gobject, prop_name, &value);

    info.GetReturnValue ().Set (GValueToV8 (isolate, &value));
}

static void ObjectPropertySetter(Local<String> name,
                                 Local<Value> value,
                                 const PropertyCallbackInfo<void> &info)
{
    /* TODO: Setting properties. */
}

static Local<String> JSPropName(Isolate *isolate, GIBaseInfo *prop_info)
{
    const char *prop_name = g_base_info_get_name ((GIBaseInfo *) prop_info);
    char *js_name = g_strdup (prop_name);

    /* Replace all hyphens with underscores. */
    for (char *c = js_name; *c; c++) {
        if (*c == '-')
            *c = '_';
    }

    Local<String> ret = String::NewFromUtf8 (isolate, js_name);
    g_free (js_name);
    return ret;
}

static void DefineObjectProperties(Isolate *isolate, Handle<ObjectTemplate> prototype, GIBaseInfo *info) {
    int n_properties = g_object_info_get_n_properties (info);

    for (int i = 0; i < n_properties; i++) {
        GIPropertyInfo *prop_info = g_object_info_get_property (info, i);

        prototype->SetNativeDataProperty (JSPropName (isolate, prop_info),
                                          ObjectPropertyGetter,
                                          ObjectPropertySetter);

        g_base_info_unref ((GIBaseInfo *) prop_info);
    }
}

static void SignalConnectInternal(const FunctionCallbackInfo<Value> &args, bool after) {
    Isolate *isolate = args.GetIsolate ();
    GObject *gobject = GObjectFromWrapper (args.This ());

    String::Utf8Value signal_name (args[0]->ToString ());
    Handle<Function> callback = Local<Function>::Cast (args[1]->ToObject ());
    GClosure *gclosure = MakeClosure (isolate, callback);

    ulong handler_id = g_signal_connect_closure (gobject, *signal_name, gclosure, after);
    args.GetReturnValue ().Set(Integer::NewFromUnsigned (isolate, handler_id));
}

static void SignalConnect(const FunctionCallbackInfo<Value> &args) {
    SignalConnectInternal (args, false);
}

static Handle<FunctionTemplate> GetBaseClassTemplate(Isolate *isolate) {
    Local<FunctionTemplate> tpl = FunctionTemplate::New (isolate);
    Handle<ObjectTemplate> proto = tpl->PrototypeTemplate ();
    proto->Set (String::NewFromUtf8 (isolate, "connect"), FunctionTemplate::New (isolate, SignalConnect)->GetFunction ());
    return tpl;
}

static Handle<FunctionTemplate> GetClassTemplateFromGI(Isolate *isolate, GIBaseInfo *info);

static void ClassDestroyed(const WeakCallbackData<FunctionTemplate, GIBaseInfo> &data) {
    GIBaseInfo *info = data.GetParameter ();
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);

    void *type_data = g_type_get_qdata (gtype, gnode_js_template_quark ());
    assert (type_data != NULL);
    Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) type_data;
    delete persistent;

    g_type_set_qdata (gtype, gnode_js_template_quark (), NULL);
    g_base_info_unref (info);
}

static Handle<FunctionTemplate> GetClassTemplate(Isolate *isolate, GIBaseInfo *info, GType gtype) {
    void *data = g_type_get_qdata (gtype, gnode_js_template_quark ());

    if (data) {
        Persistent<FunctionTemplate> *persistent = (Persistent<FunctionTemplate> *) data;
        Handle<FunctionTemplate> tpl = Handle<FunctionTemplate>::New (isolate, *persistent);
        return tpl;
    } else {
        Handle<FunctionTemplate> tpl = FunctionTemplate::New (isolate, GObjectConstructor, External::New (isolate, info));

        Persistent<FunctionTemplate> *persistent = new Persistent<FunctionTemplate>(isolate, tpl);
        persistent->SetWeak (g_base_info_ref (info), ClassDestroyed);
        g_type_set_qdata (gtype, gnode_js_template_quark (), persistent);

        const char *class_name = g_base_info_get_name (info);
        tpl->SetClassName (String::NewFromUtf8 (isolate, class_name));

        tpl->InstanceTemplate ()->SetInternalFieldCount (1);

        DefineConstructorMethods (isolate, tpl, info);
        DefinePrototypeMethods (isolate, tpl->PrototypeTemplate (), info);
        DefineObjectProperties (isolate, tpl->InstanceTemplate (), info);

        GIObjectInfo *parent_info = g_object_info_get_parent (info);
        if (parent_info) {
            Handle<FunctionTemplate> parent_tpl = GetClassTemplateFromGI (isolate, (GIBaseInfo *) parent_info);
            tpl->Inherit (parent_tpl);
        } else {
            tpl->Inherit (GetBaseClassTemplate (isolate));
        }

        return tpl;
    }
}

static Handle<FunctionTemplate> GetClassTemplateFromGI(Isolate *isolate, GIBaseInfo *info) {
    GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info);
    return GetClassTemplate (isolate, info, gtype);
}

static Handle<FunctionTemplate> GetClassTemplateFromGType(Isolate *isolate, GType gtype) {
    GIRepository *repo = g_irepository_get_default ();
    GIBaseInfo *info = g_irepository_find_by_gtype (repo, gtype);
    return GetClassTemplate (isolate, info, gtype);
}

Handle<Function> MakeClass(Isolate *isolate, GIBaseInfo *info) {
    Handle<FunctionTemplate> tpl = GetClassTemplateFromGI (isolate, info);
    return tpl->GetFunction ();
}

static void ObjectDestroyed(const WeakCallbackData<Object, GObject> &data) {
    GObject *gobject = data.GetParameter ();

    void *type_data = g_object_get_qdata (gobject, gnode_js_object_quark ());
    assert (type_data != NULL);
    Persistent<Object> *persistent = (Persistent<Object> *) type_data;
    delete persistent;

    /* We're destroying the wrapper object, so make sure to clear out
     * the qdata that points back to us. */
    g_object_set_qdata (gobject, gnode_js_object_quark (), NULL);

    g_object_unref (gobject);
}

static void ToggleNotify(gpointer user_data, GObject *gobject, gboolean toggle_down) {
    void *data = g_object_get_qdata (gobject, gnode_js_object_quark ());
    assert (data != NULL);

    Persistent<Object> *persistent = (Persistent<Object> *) data;

    if (toggle_down) {
        /* We're dropping from 2 refs to 1 ref. We are the last holder. Make
         * sure that that our weak ref is installed. */
        persistent->SetWeak (gobject, ObjectDestroyed);
    } else {
        /* We're going from 1 ref to 2 refs. We can't let our wrapper be
         * collected, so make sure that our reference is persistent */
        persistent->ClearWeak ();
    }
}

Handle<Value> WrapperFromGObject(Isolate *isolate, GObject *gobject) {
    void *data = g_object_get_qdata (gobject, gnode_js_object_quark ());

    if (data) {
        /* Easy case: we already have an object. */
        Persistent<Object> *persistent = (Persistent<Object> *) data;
        Handle<Object> obj = Handle<Object>::New (isolate, *persistent);
        return obj;
    } else {
        GType gtype = G_OBJECT_TYPE (gobject);

        Handle<FunctionTemplate> tpl = GetClassTemplateFromGType (isolate, gtype);
        Handle<Function> constructor = tpl->GetFunction ();

        Handle<Value> gobject_external = External::New (isolate, gobject);
        Handle<Value> args[] = { gobject_external };
        Handle<Object> obj = constructor->NewInstance (1, args);
        return obj;
    }
}

GObject * GObjectFromWrapper(Handle<Value> value) {
    Handle<Object> object = value->ToObject ();
    void *data = object->GetAlignedPointerFromInternalField (0);
    GObject *gobject = G_OBJECT (data);
    return gobject;
}

};
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include "itkArray2D.h"

//#include <vigra/random_forest_hdf5_impex.hxx>
#include <mitkLibSVMClassifier.h>
#include <itkLabelSampler.h>
#include <mitkImageCast.h>
#include <mitkStandaloneDataStorage.h>
#include <itkCSVArray2DFileReader.h>
#include <itkCSVArray2DDataObject.h>

//#include <boost/algorithm/string.hpp>

class mitkLibSVMClassifierTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkLibSVMClassifierTestSuite  );

  MITK_TEST(TrainSVMClassifier);
//  MITK_TEST(TestThreadedDecisionForest);

  CPPUNIT_TEST_SUITE_END();

private:

 // typedef mitk::ImageToEigenTransform::VectorType EigenVectorType;
//  static std::string GetTestDataFilePath(const std::string& testData)
//  {
//    if (itksys::SystemTools::FileIsFullPath(testData.c_str())) return testData;
//    return std::string(MITK_MBI_DATA_DIR) + "/" + testData;
//  }

//  mitk::DecisionForest::Pointer m_EmptyDecisionForest, m_LoadedDecisionForest;
//  mitk::DataCollection::Pointer m_TrainDatacollection;
//  mitk::DataCollection::Pointer m_TestDatacollection;
  mitk::Image::Pointer inputImage;
  mitk::Image::Pointer classMask;
  mitk::Image::Pointer F1;
  mitk::Image::Pointer F2;
  mitk::Image::Pointer F3;
  Eigen::MatrixXd Matrix_X;
  Eigen::MatrixXi Matrix_y;
  Eigen::MatrixXd X_predict;

  mitk::LibSVMClassifier::Pointer classifier;

public:

  void MergeLabels(std::map<unsigned int, unsigned int> map, mitk::Image::Pointer img)
  {

    itk::Image<unsigned int, 3>::Pointer classImage;
    mitk::CastToItkImage(img, classImage);
    auto it = itk::ImageRegionIterator<itk::Image<unsigned int, 3> >(classImage,classImage->GetLargestPossibleRegion());
    it.GoToBegin();

    while(!it.IsAtEnd())
    {
      if(map.find(it.Value())!=map.end())
        it.Set( map[it.Value()] );
      ++it;
    }

    mitk::CastToMitkImage(classImage,img);

  }

  /* Liet einen File und somit die Trainings- und Testdatenstze ein und
     konvertiert den Inhalt des Files in eine 2dim Matrix.
  */
  template<typename T>
  Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> convertCSVToMatrix(const std::string &path, char delimiter)
  {
    itk::CSVArray2DFileReader<T>::Pointer fr = itk::CSVArray2DFileReader<T>::New();
    fr->SetFileName(path);
    fr->SetFieldDelimiterCharacter(delimiter);
    fr->HasColumnHeadersOff();
    fr->HasRowHeadersOff();
    fr->Parse();
    try{
        fr->Update();
    }catch(itk::ExceptionObject& ex){
        cout << "Exception caught!" << std::endl;
        cout << ex << std::endl;
    }

    itk::CSVArray2DDataObject<T>::Pointer p = fr->GetOutput();
    Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> out_mat;
    unsigned int r = p->GetMatrix().rows();
    unsigned int c = p->GetMatrix().cols();
    out_mat = Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic>(r,c);

    for(int row = 0; row < r; row++){
        for(int col = 0; col < c; col++){
        out_mat(row,col) =  p->GetData(row,col);
        }
    }

    return out_mat;
  }

  void setUp(void)
  {

    /*  itk::CSVArray2DFileReader<double>::Pointer fr = itk::CSVArray2DFileReader<double>::New();
    itk::CSVArray2DFileReader<int>::Pointer fr2 = itk::CSVArray2DFileReader<int>::New();

    fr->SetFileName("C:/Users/tschlats/Desktop/data.csv");
    fr->SetFieldDelimiterCharacter(';');
    fr->HasColumnHeadersOff();
    fr->HasRowHeadersOff();
    fr->Parse();
    try{
        fr->Update();
    }catch(itk::ExceptionObject& ex){
    cout << "Exception caught!" << std::endl;
    cout << ex << std::endl;
    }

    fr2->SetFileName("C:/Users/tschlats/Desktop/dataY.csv");
    fr2->SetFieldDelimiterCharacter(' ');
    fr2->HasColumnHeadersOff();
    fr2->HasRowHeadersOff();
    fr2->Parse();
    try{
        fr2->Update();
    }catch(itk::ExceptionObject& ex){
    cout << "Exception caught!" << std::endl;
    cout << ex << std::endl;
    }

    itk::CSVArray2DDataObject<double>::ConstPointer p = fr->GetOutput();
    itk::CSVArray2DDataObject<int>::ConstPointer p2 = fr2->GetOutput();
    Matrix_X = Eigen::MatrixXd(683,10); // Trainingsdatenmatrix
    Matrix_y = Eigen::MatrixXi(683,1);  // Testdatenmatrix   */

    Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> trainingMatrix = convertCSVToMatrix<double>("C:/Users/tschlats/Desktop/data.csv",';');
    Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic> testMatrix = convertCSVToMatrix<int>("C:/Users/tschlats/Desktop/dataY.csv",';');
    cout << trainingMatrix << endl;

    /*  // liefert double Werte zurck da MatrixXd
    for(int row = 0; row < Matrix_X.rows() ; row++){
        for(int col = 0; col < Matrix_X.cols() ; col++){
        Matrix_X(row,col) =  p->GetData(row,col);
        }
    }

    // liefert int Werte zurck da MatrixXi
    for(int i = 0; i < Matrix_y.rows(); i++){
    Matrix_y(i,0) = p2->GetData(i,0);
    }   */

    //  cout << Matrix_X << endl;
    //  cout << Matrix_y << endl;

    /*
    // Load Image Data
    inputImage = mitk::IOUtil::LoadImage(GetTestDataFilePath("Classification/Classifier/InputImage.nrrd"));
    classMask = mitk::IOUtil::LoadImage(GetTestDataFilePath("Classification/Classifier/ClassMask.nrrd"));
    F1 = mitk::IOUtil::LoadImage(GetTestDataFilePath("Classification/Classifier/F1.nrrd"));

    std::map<unsigned int, unsigned int> map;
    map[0] = 0;
    map[1] = 1;
    map[2] = 1;
    map[3] = 2;
    MergeLabels(map,classMask);

    itk::Image<unsigned char,3>::Pointer itkClass;
    mitk::CastToItkImage(classMask,itkClass);

    itk::LabelSampler<itk::Image<unsigned char,3> >::Pointer filter = itk::LabelSampler<itk::Image<unsigned char,3> >::New();
    filter->SetInput(itkClass);
    filter->SetAcceptRate(0.01);
    filter->Update();

    mitk::Image::Pointer sampledClassMask;
    mitk::CastToMitkImage(filter->GetOutput(), sampledClassMask); */

//    // Initialize X
//    Eigen::MatrixXd vec = mitk::ImageToEigenTransform::transform(inputImage,sampledClassMask);
//    unsigned int n_features = 4; // F1,F2,F3 and inputImage
//    unsigned int n_samples = vec.rows();

//    X = Eigen::MatrixXd(n_samples,n_features);
//    X.col(0) = vec;
//    X.col(1) = mitk::ImageToEigenTransform::transform(F1,sampledClassMask);

//    y = mitk::ImageToEigenTransform::transform(classMask,sampledClassMask);

//    vec = mitk::ImageToEigenTransform::transform(inputImage,classMask);
//    n_samples = vec.rows();

//    X_predict = Eigen::MatrixXd(n_samples,n_features);
//    X_predict.col(0) = vec;
//    X_predict.col(1) = mitk::ImageToEigenTransform::transform(F1,classMask);

//    MITK_INFO << "Shape of X [" << X.rows() << " " << X.cols() << "]";
//    MITK_INFO << "Shape of X_predict [" << X_predict.rows() << " " << X_predict.cols() << "]";
//    MITK_INFO << "Shape of Y [" << y.rows() << "]";

//    classifier = mitk::LibSVMClassifier::New();

  }

  /* Task: Ld ein 3dim-Bild und zhlt alle Voxel, die > 0 sind und gibt das
     Ergebnis auf der Konsole aus.
  */
  void TrainSVMClassifier()
  {
    /* mitk::Image::Pointer mitkfirstImage;
    typedef itk::Image<unsigned int,3> ImageType;
    itk::Image<unsigned int,3>::Pointer itkfirstImage; // 3dim Bild.

    mitkfirstImage = mitk::IOUtil::LoadImage("c:/bachelor/bin/MITK-Data/Pic3D.nrrd");
    mitk::CastToItkImage(mitkfirstImage,itkfirstImage);

    // a) mit dem Iterator

    // auto = autom. Datentyp hier ist auto = itk::ImageRegionIterator<itk::Image<unsigned int, 3>
    //                                                                Bild ,        Region
    // allg: itk::ImageRegionIterator<ImageType> imageIterator(image,region);
    auto it = itk::ImageRegionIterator<itk::Image<unsigned int, 3> >(itkfirstImage,itkfirstImage->GetLargestPossibleRegion());
    it.GoToBegin();
    unsigned int greyValues = 0;

    while(!it.IsAtEnd())
    {
    greyValues += it.Get();   // unsigned = ohne Vorzeichen.

      ++it;
    }
    MITK_INFO << "Loading of the Image was successfully with iterator" << greyValues;

    // GetImageDimension ansehen !!

    // b) mit dreifachgeschachtelter FOR-Schleife
    unsigned int a =  0;
//  cout << itkfirstImage->GetLargestPossibleRegion().GetSize()[0] << endl; // 256 xDim
//  cout << itkfirstImage->GetLargestPossibleRegion().GetSize()[1] << endl; // 256 yDim
//  cout << itkfirstImage->GetLargestPossibleRegion().GetSize()[2] << endl; //49  zDim

    for(int z = 0; z < itkfirstImage->GetLargestPossibleRegion().GetSize()[2]   ; z++){
        for(int y = 0; y < itkfirstImage->GetLargestPossibleRegion().GetSize()[1]  ; y++){
            for(int x = 0; x < itkfirstImage->GetLargestPossibleRegion().GetSize()[0]  ; x++){
                // do something
                    ImageType::IndexType pixelIndex;
                    pixelIndex[0] = x;
                    pixelIndex[1] = y;
                    pixelIndex[2] = z;
                    a += itkfirstImage->GetPixel(pixelIndex);
    }
        }
            }

    MITK_INFO << "Loading of the Image was successfully with For Loops" << a; */

    classifier->Train(Matrix_X,Matrix_y);
     Eigen::MatrixXi classes = classifier->Predict(X_predict);
    cout << classes << endl;

   // mitk::Image::Pointer img = mitk::EigenToImageTransform::transform(classes, classMask);
   // mitk::IOUtil::Save(img,"/Users/jc/prediction.nrrd");
  }

  void TestThreadedDecisionForest()
  {
//    m_LoadedDecisionForest->SetCollection(m_TrainDatacollection);
//    m_LoadedDecisionForest->SetModalities(m_Selected_items);
//    m_LoadedDecisionForest->SetResultProb("ResultProb");
//    m_LoadedDecisionForest->TestThreaded();

    //    mitk::DataCollection::Pointer res_col = dynamic_cast<mitk::DataCollection *>(dynamic_cast<mitk::DataCollection *>(m_TrainDatacollection->GetData("Test-Study").GetPointer())->GetData("Test-Subject").GetPointer());
    //    mitk::IOUtil::Save(res_col->GetMitkImage("ResultMask"),"/Users/jc/res_mask.nrrd");
    //    mitk::IOUtil::Save(res_col->GetMitkImage("ResultProb_Class-0"),"/Users/jc/res_prob_0.nrrd");
    //    mitk::IOUtil::Save(res_col->GetMitkImage("ResultProb_Class-1"),"/Users/jc/res_prob_1.nrrd");
    //    mitk::IOUtil::Save(res_col->GetMitkImage("ResultProb_Class-2"),"/Users/jc/res_prob_2.nrrd");
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkLibSVMClassifier)

<commit_msg>testSVM creating matrix for training and testing<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include "itkArray2D.h"

//#include <vigra/random_forest_hdf5_impex.hxx>
#include <mitkLibSVMClassifier.h>
#include <itkLabelSampler.h>
#include <mitkImageCast.h>
#include <mitkStandaloneDataStorage.h>
#include <itkCSVArray2DFileReader.h>
#include <itkCSVArray2DDataObject.h>

//#include <boost/algorithm/string.hpp>

class mitkLibSVMClassifierTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkLibSVMClassifierTestSuite  );

  MITK_TEST(TrainSVMClassifier);
//  MITK_TEST(TestThreadedDecisionForest);

  CPPUNIT_TEST_SUITE_END();

private:

  typedef Eigen::Matrix<double ,Eigen::Dynamic,Eigen::Dynamic> MatrixDoubleType;
  typedef Eigen::Matrix<int, Eigen::Dynamic,Eigen::Dynamic> MatrixIntType;

  Eigen::MatrixXd m_TrainingMatrixX;
  Eigen::MatrixXi m_TrainingLabelMatrixY;
  Eigen::MatrixXd m_TestXPredict;
  Eigen::MatrixXi m_TestYPredict;

  mitk::LibSVMClassifier::Pointer classifier;

public:

  /* Liet einen File und somit die Trainings- und Testdatenstze ein und
     konvertiert den Inhalt des Files in eine 2dim Matrix.
  */

   template<typename T>
   std::pair<Eigen::Matrix<T ,Eigen::Dynamic,Eigen::Dynamic>,Eigen::Matrix<T ,Eigen::Dynamic,Eigen::Dynamic> >convertCSVToMatrix(const std::string &path, char delimiter,double range, bool isXMatrix)
  {
    itk::CSVArray2DFileReader<T>::Pointer fr = itk::CSVArray2DFileReader<T>::New();
      fr->SetFileName(path);
      fr->SetFieldDelimiterCharacter(delimiter);
      fr->HasColumnHeadersOff();
      fr->HasRowHeadersOff();
      fr->Parse();
      try{
        fr->Update();
      }catch(itk::ExceptionObject& ex){
        cout << "Exception caught!" << std::endl;
        cout << ex << std::endl;
    }

         itk::CSVArray2DDataObject<T>::Pointer p = fr->GetOutput();
         unsigned int maxrowrange = p->GetMatrix().rows();
         unsigned int c = p->GetMatrix().cols();
         unsigned int percentRange = (unsigned int)(maxrowrange*range);

    if(isXMatrix == true){

      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> trainMatrixX(percentRange,c);
      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> testMatrixXPredict(maxrowrange,c);

        for(int row = 0; row < percentRange; row++){
          for(int col = 0; col < c; col++){
             trainMatrixX(row,col) =  p->GetData(row,col);
          }
        }

         for(int row = percentRange; row < maxrowrange; row++){
            for(int col = 0; col < c; col++){
                testMatrixXPredict(row,col) =  p->GetData(row,col);
        }
    }

    return std::make_pair(trainMatrixX,testMatrixXPredict);
    }
    else if(isXMatrix == false){

      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> trainLabelMatrixY(percentRange,c);
      Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> testMatrixYPredict(maxrowrange,c);

         for(int row = 0; row < percentRange; row++){
           for(int col = 0; col < c; col++){
             trainLabelMatrixY(row,col) =  p->GetData(row,col);
          }
        }

          for(int row = percentRange; row < maxrowrange; row++){
            for(int col = 0; col < c; col++){
                testMatrixYPredict(row,col) =  p->GetData(row,col);
        }
    }

    return std::make_pair(trainLabelMatrixY,testMatrixYPredict);
    }
  }

  void setUp(void)
  {

    std::pair<MatrixDoubleType,MatrixDoubleType> matrixDouble;
    matrixDouble = convertCSVToMatrix<double>("C:/Users/tschlats/Desktop/data.csv",';',0.5,true);
    m_TrainingMatrixX = matrixDouble.first;
    m_TestXPredict = matrixDouble.second;

    std::pair<MatrixIntType,MatrixIntType> matrixInt;
    matrixInt = convertCSVToMatrix<int>("C:/Users/tschlats/Desktop/dataY.csv",';',0.5,false);
    m_TrainingLabelMatrixY = matrixInt.first;
    m_TestYPredict = matrixInt.second;
    classifier = mitk::LibSVMClassifier::New();

  }

  void TrainSVMClassifier()
  {

    MITK_INFO << "start SVM-Training";

    classifier->Train(m_TrainingMatrixX,m_TrainingLabelMatrixY);
  /*  Eigen::MatrixXi classes = classifier->Predict(test_X_predict);
    cout << classes << endl; */

   // mitk::Image::Pointer img = mitk::EigenToImageTransform::transform(classes, classMask);
   // mitk::IOUtil::Save(img,"/Users/jc/prediction.nrrd");
  }

  void TestThreadedDecisionForest()
  {
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkLibSVMClassifier)

<|endoftext|>


<commit_before>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

#include <google/protobuf/compiler/cpp/cpp_service.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {

ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
                                   const string& dllexport_decl)
  : descriptor_(descriptor) {
  vars_["classname"] = descriptor_->name();
  vars_["full_name"] = descriptor_->full_name();
  if (dllexport_decl.empty()) {
    vars_["dllexport"] = "";
  } else {
    vars_["dllexport"] = dllexport_decl + " ";
  }
}

ServiceGenerator::~ServiceGenerator() {}

void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
  // Forward-declare the stub type.
  printer->Print(vars_,
    "class $classname$_Stub;\n"
    "\n");

  GenerateInterface(printer);
  GenerateStubDefinition(printer);
}

void ServiceGenerator::GenerateInterface(io::Printer* printer) {
  printer->Print(vars_,
    "class $dllexport$$classname$ : public ::google::protobuf::Service {\n"
    " protected:\n"
    "  // This class should be treated as an abstract interface.\n"
    "  inline $classname$() {};\n"
    " public:\n"
    "  virtual ~$classname$();\n");
  printer->Indent();

  printer->Print(vars_,
    "\n"
    "typedef $classname$_Stub Stub;\n"
    "\n"
    "static const ::google::protobuf::ServiceDescriptor* descriptor();\n"
    "\n");

  GenerateMethodSignatures(VIRTUAL, printer);

  printer->Print(
    "\n"
    "// implements Service ----------------------------------------------\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n"
    "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
    "                ::google::protobuf::RpcController* controller,\n"
    "                const ::google::protobuf::Message* request,\n"
    "                ::google::protobuf::Message* response,\n"
    "                ::google::protobuf::Closure* done);\n"
    "const ::google::protobuf::Message& GetRequestPrototype(\n"
    "  const ::google::protobuf::MethodDescriptor* method) const;\n"
    "const ::google::protobuf::Message& GetResponsePrototype(\n"
    "  const ::google::protobuf::MethodDescriptor* method) const;\n");

  printer->Outdent();
  printer->Print(vars_,
    "\n"
    " private:\n"
    "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
    "};\n"
    "\n");
}

void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
  printer->Print(vars_,
    "class $dllexport$$classname$_Stub : public $classname$ {\n"
    " public:\n");

  printer->Indent();

  printer->Print(vars_,
    "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n"
    "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n"
    "                 ::google::protobuf::Service::ChannelOwnership ownership);\n"
    "~$classname$_Stub();\n"
    "\n"
    "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n"
    "\n"
    "// implements $classname$ ------------------------------------------\n"
    "\n");

  GenerateMethodSignatures(NON_VIRTUAL, printer);

  printer->Outdent();
  printer->Print(vars_,
    " private:\n"
    "  ::google::protobuf::RpcChannel* channel_;\n"
    "  bool owns_channel_;\n"
    "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n"
    "};\n"
    "\n");
}

void ServiceGenerator::GenerateMethodSignatures(
    VirtualOrNon virtual_or_non, io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["name"] = method->name();
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);
    sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : "";

    printer->Print(sub_vars,
      "$virtual$void $name$(::google::protobuf::RpcController* controller,\n"
      "                     const $input_type$* request,\n"
      "                     $output_type$* response,\n"
      "                     ::google::protobuf::Closure* done);\n");
  }
}

// ===================================================================

void ServiceGenerator::GenerateDescriptorInitializer(
    io::Printer* printer, int index) {
  map<string, string> vars;
  vars["classname"] = descriptor_->name();
  vars["index"] = SimpleItoa(index);

  printer->Print(vars,
    "$classname$_descriptor_ = file->service($index$);\n");
}

// ===================================================================

void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
  printer->Print(vars_,
    "$classname$::~$classname$() {}\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n"
    "  return $classname$_descriptor_;\n"
    "}\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n"
    "  return $classname$_descriptor_;\n"
    "}\n"
    "\n");

  // Generate methods of the interface.
  GenerateNotImplementedMethods(printer);
  GenerateCallMethod(printer);
  GenerateGetPrototype(REQUEST, printer);
  GenerateGetPrototype(RESPONSE, printer);

  // Generate stub implementation.
  printer->Print(vars_,
    "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n"
    "  : channel_(channel), owns_channel_(false) {}\n"
    "$classname$_Stub::$classname$_Stub(\n"
    "    ::google::protobuf::RpcChannel* channel,\n"
    "    ::google::protobuf::Service::ChannelOwnership ownership)\n"
    "  : channel_(channel),\n"
    "    owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n"
    "$classname$_Stub::~$classname$_Stub() {\n"
    "  if (owns_channel_) delete channel_;\n"
    "}\n"
    "\n");

  GenerateStubMethods(printer);
}

void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["classname"] = descriptor_->name();
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    printer->Print(sub_vars,
      "void $classname$::$name$(::google::protobuf::RpcController* controller,\n"
      "                         const $input_type$* request,\n"
      "                         $output_type$* response,\n"
      "                         ::google::protobuf::Closure* done) {\n"
      "  controller->SetFailed(\"Method $name$() not implemented.\");\n"
      "  done->Run();\n"
      "}\n"
      "\n");
  }
}

void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
  printer->Print(vars_,
    "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
    "                             ::google::protobuf::RpcController* controller,\n"
    "                             const ::google::protobuf::Message* request,\n"
    "                             ::google::protobuf::Message* response,\n"
    "                             ::google::protobuf::Closure* done) {\n"
    "  GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
    "  switch(method->index()) {\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    // Note:  ::google::protobuf::down_cast does not work here because it only works on pointers,
    //   not references.
    printer->Print(sub_vars,
      "    case $index$:\n"
      "      $name$(controller,\n"
      "             ::google::protobuf::down_cast<const $input_type$*>(request),\n"
      "             ::google::protobuf::down_cast< $output_type$*>(response),\n"
      "             done);\n"
      "      break;\n");
  }

  printer->Print(vars_,
    "    default:\n"
    "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
    "      break;\n"
    "  }\n"
    "}\n"
    "\n");
}

void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
                                            io::Printer* printer) {
  if (which == REQUEST) {
    printer->Print(vars_,
      "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
  } else {
    printer->Print(vars_,
      "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n");
  }

  printer->Print(vars_,
    "    const ::google::protobuf::MethodDescriptor* method) const {\n"
    "  GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
    "  switch(method->index()) {\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    const Descriptor* type =
      (which == REQUEST) ? method->input_type() : method->output_type();

    map<string, string> sub_vars;
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["type"] = ClassName(type, true);

    printer->Print(sub_vars,
      "    case $index$:\n"
      "      return $type$::default_instance();\n");
  }

  printer->Print(vars_,
    "    default:\n"
    "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
    "      return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
    "  }\n"
    "}\n"
    "\n");
}

void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["classname"] = descriptor_->name();
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    printer->Print(sub_vars,
      "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n"
      "                              const $input_type$* request,\n"
      "                              $output_type$* response,\n"
      "                              ::google::protobuf::Closure* done) {\n"
      "  channel_->CallMethod($classname$_descriptor_->method($index$),\n"
      "                       controller, request, response, done);\n"
      "}\n");
  }
}

}  // namespace cpp
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<commit_msg>Avoid an "unused parameter" warning when using high warning levels.<commit_after>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// http://code.google.com/p/protobuf/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.

#include <google/protobuf/compiler/cpp/cpp_service.h>
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {

ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor,
                                   const string& dllexport_decl)
  : descriptor_(descriptor) {
  vars_["classname"] = descriptor_->name();
  vars_["full_name"] = descriptor_->full_name();
  if (dllexport_decl.empty()) {
    vars_["dllexport"] = "";
  } else {
    vars_["dllexport"] = dllexport_decl + " ";
  }
}

ServiceGenerator::~ServiceGenerator() {}

void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
  // Forward-declare the stub type.
  printer->Print(vars_,
    "class $classname$_Stub;\n"
    "\n");

  GenerateInterface(printer);
  GenerateStubDefinition(printer);
}

void ServiceGenerator::GenerateInterface(io::Printer* printer) {
  printer->Print(vars_,
    "class $dllexport$$classname$ : public ::google::protobuf::Service {\n"
    " protected:\n"
    "  // This class should be treated as an abstract interface.\n"
    "  inline $classname$() {};\n"
    " public:\n"
    "  virtual ~$classname$();\n");
  printer->Indent();

  printer->Print(vars_,
    "\n"
    "typedef $classname$_Stub Stub;\n"
    "\n"
    "static const ::google::protobuf::ServiceDescriptor* descriptor();\n"
    "\n");

  GenerateMethodSignatures(VIRTUAL, printer);

  printer->Print(
    "\n"
    "// implements Service ----------------------------------------------\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n"
    "void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
    "                ::google::protobuf::RpcController* controller,\n"
    "                const ::google::protobuf::Message* request,\n"
    "                ::google::protobuf::Message* response,\n"
    "                ::google::protobuf::Closure* done);\n"
    "const ::google::protobuf::Message& GetRequestPrototype(\n"
    "  const ::google::protobuf::MethodDescriptor* method) const;\n"
    "const ::google::protobuf::Message& GetResponsePrototype(\n"
    "  const ::google::protobuf::MethodDescriptor* method) const;\n");

  printer->Outdent();
  printer->Print(vars_,
    "\n"
    " private:\n"
    "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n"
    "};\n"
    "\n");
}

void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) {
  printer->Print(vars_,
    "class $dllexport$$classname$_Stub : public $classname$ {\n"
    " public:\n");

  printer->Indent();

  printer->Print(vars_,
    "$classname$_Stub(::google::protobuf::RpcChannel* channel);\n"
    "$classname$_Stub(::google::protobuf::RpcChannel* channel,\n"
    "                 ::google::protobuf::Service::ChannelOwnership ownership);\n"
    "~$classname$_Stub();\n"
    "\n"
    "inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n"
    "\n"
    "// implements $classname$ ------------------------------------------\n"
    "\n");

  GenerateMethodSignatures(NON_VIRTUAL, printer);

  printer->Outdent();
  printer->Print(vars_,
    " private:\n"
    "  ::google::protobuf::RpcChannel* channel_;\n"
    "  bool owns_channel_;\n"
    "  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n"
    "};\n"
    "\n");
}

void ServiceGenerator::GenerateMethodSignatures(
    VirtualOrNon virtual_or_non, io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["name"] = method->name();
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);
    sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : "";

    printer->Print(sub_vars,
      "$virtual$void $name$(::google::protobuf::RpcController* controller,\n"
      "                     const $input_type$* request,\n"
      "                     $output_type$* response,\n"
      "                     ::google::protobuf::Closure* done);\n");
  }
}

// ===================================================================

void ServiceGenerator::GenerateDescriptorInitializer(
    io::Printer* printer, int index) {
  map<string, string> vars;
  vars["classname"] = descriptor_->name();
  vars["index"] = SimpleItoa(index);

  printer->Print(vars,
    "$classname$_descriptor_ = file->service($index$);\n");
}

// ===================================================================

void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
  printer->Print(vars_,
    "$classname$::~$classname$() {}\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n"
    "  return $classname$_descriptor_;\n"
    "}\n"
    "\n"
    "const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n"
    "  return $classname$_descriptor_;\n"
    "}\n"
    "\n");

  // Generate methods of the interface.
  GenerateNotImplementedMethods(printer);
  GenerateCallMethod(printer);
  GenerateGetPrototype(REQUEST, printer);
  GenerateGetPrototype(RESPONSE, printer);

  // Generate stub implementation.
  printer->Print(vars_,
    "$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n"
    "  : channel_(channel), owns_channel_(false) {}\n"
    "$classname$_Stub::$classname$_Stub(\n"
    "    ::google::protobuf::RpcChannel* channel,\n"
    "    ::google::protobuf::Service::ChannelOwnership ownership)\n"
    "  : channel_(channel),\n"
    "    owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n"
    "$classname$_Stub::~$classname$_Stub() {\n"
    "  if (owns_channel_) delete channel_;\n"
    "}\n"
    "\n");

  GenerateStubMethods(printer);
}

void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["classname"] = descriptor_->name();
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    printer->Print(sub_vars,
      "void $classname$::$name$(::google::protobuf::RpcController* controller,\n"
      "                         const $input_type$*,\n"
      "                         $output_type$*,\n"
      "                         ::google::protobuf::Closure* done) {\n"
      "  controller->SetFailed(\"Method $name$() not implemented.\");\n"
      "  done->Run();\n"
      "}\n"
      "\n");
  }
}

void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
  printer->Print(vars_,
    "void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n"
    "                             ::google::protobuf::RpcController* controller,\n"
    "                             const ::google::protobuf::Message* request,\n"
    "                             ::google::protobuf::Message* response,\n"
    "                             ::google::protobuf::Closure* done) {\n"
    "  GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
    "  switch(method->index()) {\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    // Note:  ::google::protobuf::down_cast does not work here because it only works on pointers,
    //   not references.
    printer->Print(sub_vars,
      "    case $index$:\n"
      "      $name$(controller,\n"
      "             ::google::protobuf::down_cast<const $input_type$*>(request),\n"
      "             ::google::protobuf::down_cast< $output_type$*>(response),\n"
      "             done);\n"
      "      break;\n");
  }

  printer->Print(vars_,
    "    default:\n"
    "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
    "      break;\n"
    "  }\n"
    "}\n"
    "\n");
}

void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
                                            io::Printer* printer) {
  if (which == REQUEST) {
    printer->Print(vars_,
      "const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n");
  } else {
    printer->Print(vars_,
      "const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n");
  }

  printer->Print(vars_,
    "    const ::google::protobuf::MethodDescriptor* method) const {\n"
    "  GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n"
    "  switch(method->index()) {\n");

  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    const Descriptor* type =
      (which == REQUEST) ? method->input_type() : method->output_type();

    map<string, string> sub_vars;
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["type"] = ClassName(type, true);

    printer->Print(sub_vars,
      "    case $index$:\n"
      "      return $type$::default_instance();\n");
  }

  printer->Print(vars_,
    "    default:\n"
    "      GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n"
    "      return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n"
    "  }\n"
    "}\n"
    "\n");
}

void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
  for (int i = 0; i < descriptor_->method_count(); i++) {
    const MethodDescriptor* method = descriptor_->method(i);
    map<string, string> sub_vars;
    sub_vars["classname"] = descriptor_->name();
    sub_vars["name"] = method->name();
    sub_vars["index"] = SimpleItoa(i);
    sub_vars["input_type"] = ClassName(method->input_type(), true);
    sub_vars["output_type"] = ClassName(method->output_type(), true);

    printer->Print(sub_vars,
      "void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n"
      "                              const $input_type$* request,\n"
      "                              $output_type$* response,\n"
      "                              ::google::protobuf::Closure* done) {\n"
      "  channel_->CallMethod($classname$_descriptor_->method($index$),\n"
      "                       controller, request, response, done);\n"
      "}\n");
  }
}

}  // namespace cpp
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<|endoftext|>


<commit_before>#include <core.h>
#include "heater.h"
#include "thermostat.h"

using namespace core;

idType idHeaterReq, idHeaterAct;

// seconds since last change heater state
uint32_t lastHeaterActionSeconds = -(HEATER_ACTION_DELAY - 60); // ensure open heater in one minute after thermostat power up.

void* currentSwitchHeaterDelay = NULL;

void doSwitchHeater() {
  currentSwitchHeaterDelay = NULL;
  lastHeaterActionSeconds = millis() / 1000;

  uint8_t req = store::digitals[idHeaterReq];
  digitalWrite(HEATER_PIN, req);
  store::setDigital(idHeaterAct, req);
}

void switchHeater() {
  if (currentSwitchHeaterDelay != NULL) {
    clock::removeDelay(currentSwitchHeaterDelay);
    currentSwitchHeaterDelay = NULL;
  }

  uint32_t current = millis() / 1000;
  uint32_t secondsSinceLastChange = current - lastHeaterActionSeconds;

  if (compareULong(HEATER_ACTION_DELAY, secondsSinceLastChange, HEATER_ACTION_DELAY) > 0) {
    currentSwitchHeaterDelay = clock::delay(
      (HEATER_ACTION_DELAY - secondsSinceLastChange) * 1000,
      doSwitchHeater);

    Serial.print(F("Ignore heater action, not reaching minimal heater action delay. "));
    Serial.println(secondsSinceLastChange);
    return;
  }

  doSwitchHeater();
}

void setupHeater(void) {
  pinMode(HEATER_PIN, OUTPUT);

  idHeaterReq = store::defineDigital();
  idHeaterAct = store::defineDigital();
  store::monitorDigitals(switchHeater, 1, idHeaterReq);
}
<commit_msg>Shutdown heater immediately if shutdown.<commit_after>#include <core.h>
#include "heater.h"
#include "thermostat.h"
#include "shutdown.h"

using namespace core;

idType idHeaterReq, idHeaterAct;

// seconds since last change heater state
uint32_t lastHeaterActionSeconds = -(HEATER_ACTION_DELAY - 60); // ensure open heater in one minute after thermostat power up.

void* currentSwitchHeaterDelay = NULL;

void doSwitchHeater() {
  currentSwitchHeaterDelay = NULL;
  lastHeaterActionSeconds = millis() / 1000;

  uint8_t req = store::digitals[idHeaterReq];
  digitalWrite(HEATER_PIN, req);
  store::setDigital(idHeaterAct, req);
}

void switchHeater() {
  if (currentSwitchHeaterDelay != NULL) {
    clock::removeDelay(currentSwitchHeaterDelay);
    currentSwitchHeaterDelay = NULL;
  }

  uint32_t current = millis() / 1000;
  uint32_t secondsSinceLastChange = current - lastHeaterActionSeconds;

  if ((compareULong(HEATER_ACTION_DELAY, secondsSinceLastChange, HEATER_ACTION_DELAY) > 0)
      && !isShutdown()) {
    currentSwitchHeaterDelay = clock::delay(
      (HEATER_ACTION_DELAY - secondsSinceLastChange) * 1000,
      doSwitchHeater);

    Serial.print(F("Ignore heater action, not reaching minimal heater action delay. "));
    Serial.println(secondsSinceLastChange);
    return;
  }

  doSwitchHeater();
}

void setupHeater(void) {
  pinMode(HEATER_PIN, OUTPUT);

  idHeaterReq = store::defineDigital();
  idHeaterAct = store::defineDigital();
  store::monitorDigitals(switchHeater, 1, idHeaterReq);
}
<|endoftext|>


<commit_before>#pragma once

#include <typeinfo>

#include "acmacs-base/rjson.hh"

#include "acmacs-base/color.hh"
#include "acmacs-draw/size.hh"

// ----------------------------------------------------------------------

namespace rjson
{
    class field_container_parent
    {
     public:
        virtual inline ~field_container_parent() {}

        virtual value& get_ref(std::string aFieldName, value&& aDefault) = 0;
        virtual const value& get_ref(std::string aFieldName, value&& aDefault) const = 0;
        virtual object& get_ref_to_object(std::string aFieldName) = 0;
        virtual void set_field(std::string aFieldName, value&& aValue) = 0;

    }; // class field_container_parent

      // ----------------------------------------------------------------------

    class field_container_toplevel : public field_container_parent
    {
     public:
        inline void use_json(rjson::value&& aData) { mData = std::move(aData); }

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return mData.get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return mData.get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline object& get_ref_to_object(std::string aFieldName) override { return mData.get_ref_to_object(aFieldName); }
        inline void set_field(std::string aFieldName, value&& aValue) override { mData.set_field(aFieldName, std::forward<value>(aValue)); }

        inline std::string to_json() const { return mData.to_json(); }

     private:
        mutable rjson::value mData = rjson::object{};

    }; // class field_container_toplevel

      // ----------------------------------------------------------------------

    class field_container_child : public field_container_parent
    {
     public:
        inline field_container_child(field_container_parent& aParent, std::string aFieldName)
            : mParent{aParent}, mFieldName{aFieldName} {}

        inline object& get_ref_to_object() { return mParent.get_ref_to_object(mFieldName); }
        inline const object& get_ref_to_object() const { return mParent.get_ref_to_object(mFieldName); }
        inline object& get_ref_to_object(std::string aFieldName) override { return get_ref_to_object().get_ref_to_object(aFieldName); }

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return get_ref_to_object().get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return get_ref_to_object().get_ref(aFieldName, std::forward<value>(aDefault)); }

        inline void set_field(std::string aFieldName, value&& aValue) override { get_ref_to_object().set_field(aFieldName, std::forward<value>(aValue)); }

        inline std::string to_json() const { return get_ref_to_object().to_json(); }

     private:
        field_container_parent& mParent;
        std::string mFieldName;

    }; // class field_container_child

      // ----------------------------------------------------------------------

    template <typename Element> class array_field_container_child
    {
     public:
        class iterator
        {
         public:
            inline iterator& operator++() { ++iter; return *this;}
            inline iterator operator++(int) { iterator retval = *this; ++(*this); return retval;}
            inline bool operator==(iterator other) const { return iter == other.iter; }
            inline bool operator!=(iterator other) const { return !(*this == other); }
            inline Element operator*() { /* std::cerr << "DEBUG: " << *iter << DEBUG_LINE_FUNC << '\n'; */ return Element{*iter}; }

            using difference_type = array::iterator::difference_type;
            using value_type = Element;
            using pointer = Element*;
            using reference = Element&;
            using iterator_category = array::iterator::iterator_category;

         private:
            array::iterator iter;
            inline iterator(array::iterator aIter) : iter(aIter) {}

            friend class array_field_container_child<Element>;
        };

        inline array_field_container_child(field_container_parent& aParent, std::string aFieldName)
            : mParent{aParent}, mFieldName{aFieldName} {}

        inline array& get_ref_to_array() { return std::get<array>(mParent.get_ref(mFieldName, array{})); }
        inline const array& get_ref_to_array() const { return std::get<array>(mParent.get_ref(mFieldName, array{})); }
        inline size_t size() const { return get_ref_to_array().size(); }
        inline bool empty() const { return get_ref_to_array().empty(); }
        inline iterator begin() const { return get_ref_to_array().begin(); }
        inline iterator end() const { return get_ref_to_array().end(); }
        inline iterator begin() { return get_ref_to_array().begin(); }
        inline iterator end() { return get_ref_to_array().end(); }

        inline Element emplace_back()
            {
                auto& ar = get_ref_to_array();
                ar.insert(object{});
                return Element{*ar.rbegin()};
            }

     private:
        field_container_parent& mParent;
        std::string mFieldName;

    }; // class array_field_container_child<>

    class array_field_container_child_element : public field_container_parent
    {
     public:
        inline array_field_container_child_element(const value& aData) : mData{aData} {}

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return const_cast<value&>(mData).get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return const_cast<value&>(mData).get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline object& get_ref_to_object(std::string aFieldName) override { return const_cast<value&>(mData).get_ref_to_object(aFieldName); }
        inline void set_field(std::string /*aFieldName*/, value&& /*aValue*/) override { throw std::runtime_error{"no array_field_container_child_element::set_field"}; }

     private:
        const value& mData;
    };

      // ----------------------------------------------------------------------

    template <typename FValue> class field_get_set
    {
     public:
        inline field_get_set(field_container_parent& aParent, std::string aFieldName, FValue&& aDefault) : mParent{aParent}, mFieldName{aFieldName}, mDefault{std::move(aDefault)} {}
        inline field_get_set(field_container_parent& aParent, std::string aFieldName, const FValue& aDefault) : mParent{aParent}, mFieldName{aFieldName}, mDefault{aDefault} {}

        inline const rjson_type<FValue>& get_value_ref() const
            {
                try {
                    return std::get<rjson_type<FValue>>(get_ref());
                }
                catch (std::bad_variant_access& /*err*/) {
                    std::cerr << "ERROR: cannot convert json to " <<  typeid(rjson_type<FValue>).name() << " (" << typeid(FValue).name() << "): " << get_ref() << '\n';
                    throw;
                }
            }

          // inline field_get_set<FValue>& operator = (FValue&& aValue) { mParent.set_field(mFieldName, to_value(aValue)); return *this; }
        inline field_get_set<FValue>& operator = (const FValue& aValue) { mParent.set_field(mFieldName, to_value(aValue)); return *this; }
        inline field_get_set<FValue>& operator = (const field_get_set<FValue>& aSource) { return operator=(static_cast<FValue>(aSource)); }

        inline bool empty() const { return static_cast<FValue>(*this).empty(); }

          // to be specialized for complex types
        inline operator FValue() const { return get_value_ref(); }

     private:
        field_container_parent& mParent;
        std::string mFieldName;
        FValue mDefault;

        // inline value& get_ref() { return mParent.get_ref(mFieldName, to_value(mDefault)); }
        inline const value& get_ref() const { return mParent.get_ref(mFieldName, to_value(mDefault)); }
        // inline rjson_type<FValue>& get_value_ref() { return std::get<rjson_type<FValue>>(get_ref()); }

    }; // class field_get_set<>

      // ----------------------------------------------------------------------
      // double: can be extracted from rjson::number and rjson::integer
      // ----------------------------------------------------------------------

    template <> inline field_get_set<double>::operator double() const
    {
        if (auto ptr_n = std::get_if<number>(&get_ref()))
            return *ptr_n;
        else if (auto ptr_i = std::get_if<integer>(&get_ref()))
            return *ptr_i;
        else {
            std::cerr << "ERROR: cannot convert json to double (from rjson::number or rjson::integer): " << get_ref() << '\n';
            throw std::bad_variant_access{};
        }
    }

      // ----------------------------------------------------------------------
      // Color
      // ----------------------------------------------------------------------

    template <> struct content_type<Color> { using type = string; };

    template <> inline field_get_set<Color>::operator Color() const { return static_cast<std::string>(get_value_ref()); }

      // ----------------------------------------------------------------------
      // Size
      // ----------------------------------------------------------------------

    template <> struct content_type<Size> { using type = array; };

    template <> inline field_get_set<Size>::operator Size() const
    {
        const auto& ar = get_value_ref(); // std::get<array>(get_ref());
        return {std::get<number>(ar[0]), std::get<number>(ar[1])};
    }

    template <> inline value to_value<Size>(const Size& aSize)
    {
        return array{number{aSize.width}, number{aSize.height}};
    }

      // ----------------------------------------------------------------------
      // TextStyle
      // ----------------------------------------------------------------------

    template <> struct content_type<TextStyle> { using type = object; };

    template <> inline field_get_set<TextStyle>::operator TextStyle() const
    {
        const auto& obj = get_value_ref(); // std::get<object>(get_ref());
        TextStyle style;
        try { style.font_family(obj.get_field<std::string>("family")); } catch (object::field_not_found&) {}
        try { style.slant(obj.get_field<std::string>("slant")); } catch (object::field_not_found&) {}
        try { style.weight(obj.get_field<std::string>("weight")); } catch (object::field_not_found&) {}
        return style;
    }

    template <> inline value to_value<TextStyle>(const TextStyle& aTextStyle)
    {
        return object{
            {"family", string{aTextStyle.font_family()}},
            {"slant", string{aTextStyle.slant_as_stirng()}},
            {"weight", string{aTextStyle.weight_as_stirng()}}
        };
    }

      // ----------------------------------------------------------------------
      // std::vector<std::string>
      // ----------------------------------------------------------------------

    template <> struct content_type<std::vector<std::string>> { using type = array; };

    template <> inline field_get_set<std::vector<std::string>>::operator std::vector<std::string>() const
    {
        const auto& ar = get_value_ref();
        std::vector<std::string> result{ar.size()};
        std::transform(ar.begin(), ar.end(), result.begin(), [](const rjson::value& elt) -> std::string { return std::get<rjson::string>(elt); });
        return result;
    }

    template <> inline value to_value<std::vector<std::string>>(const std::vector<std::string>& aData)
    {
        array ar;
        for (const auto& elt: aData)
            ar.insert(string{elt});
        return ar;
    }

} // namespace rjson

// ----------------------------------------------------------------------

template <typename FValue> inline std::ostream& operator<<(std::ostream& out, const rjson::field_get_set<FValue>& aValue)
{
    return out << static_cast<FValue>(aValue);
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>serializing CladesDrawSettings development<commit_after>#pragma once

#include <typeinfo>

#include "acmacs-base/rjson.hh"

#include "acmacs-base/color.hh"
#include "acmacs-draw/size.hh"

// ----------------------------------------------------------------------

namespace rjson
{
    class field_container_parent
    {
     public:
        virtual inline ~field_container_parent() {}

        virtual value& get_ref(std::string aFieldName, value&& aDefault) = 0;
        virtual const value& get_ref(std::string aFieldName, value&& aDefault) const = 0;
        virtual object& get_ref_to_object(std::string aFieldName) = 0;
        virtual void set_field(std::string aFieldName, value&& aValue) = 0;

    }; // class field_container_parent

      // ----------------------------------------------------------------------

    class field_container_toplevel : public field_container_parent
    {
     public:
        inline void use_json(rjson::value&& aData) { mData = std::move(aData); }

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return mData.get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return mData.get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline object& get_ref_to_object(std::string aFieldName) override { return mData.get_ref_to_object(aFieldName); }
        inline void set_field(std::string aFieldName, value&& aValue) override { mData.set_field(aFieldName, std::forward<value>(aValue)); }

        inline std::string to_json() const { return mData.to_json(); }

     private:
        mutable rjson::value mData = rjson::object{};

    }; // class field_container_toplevel

      // ----------------------------------------------------------------------

    class field_container_child : public field_container_parent
    {
     public:
        inline field_container_child(field_container_parent& aParent, std::string aFieldName)
            : mParent{aParent}, mFieldName{aFieldName} {}

        inline object& get_ref_to_object() { return mParent.get_ref_to_object(mFieldName); }
        inline const object& get_ref_to_object() const { return mParent.get_ref_to_object(mFieldName); }
        inline object& get_ref_to_object(std::string aFieldName) override { return get_ref_to_object().get_ref_to_object(aFieldName); }

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return get_ref_to_object().get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return get_ref_to_object().get_ref(aFieldName, std::forward<value>(aDefault)); }

        inline void set_field(std::string aFieldName, value&& aValue) override { get_ref_to_object().set_field(aFieldName, std::forward<value>(aValue)); }

        inline std::string to_json() const { return get_ref_to_object().to_json(); }

     private:
        field_container_parent& mParent;
        std::string mFieldName;

    }; // class field_container_child

      // ----------------------------------------------------------------------

    template <typename Element> class array_field_container_child
    {
     public:
        class iterator
        {
         public:
            inline iterator& operator++() { ++iter; return *this;}
            inline iterator operator++(int) { iterator retval = *this; ++(*this); return retval;}
            inline bool operator==(iterator other) const { return iter == other.iter; }
            inline bool operator!=(iterator other) const { return !(*this == other); }
            inline Element operator*() { /* std::cerr << "DEBUG: " << *iter << DEBUG_LINE_FUNC << '\n'; */ return Element{*iter}; }

            using difference_type = array::iterator::difference_type;
            using value_type = Element;
            using pointer = Element*;
            using reference = Element&;
            using iterator_category = array::iterator::iterator_category;

         private:
            array::iterator iter;
            inline iterator(array::iterator aIter) : iter(aIter) {}

            friend class array_field_container_child<Element>;
        };

        inline array_field_container_child(field_container_parent& aParent, std::string aFieldName)
            : mParent{aParent}, mFieldName{aFieldName} {}

        inline array& get_ref_to_array() { return std::get<array>(mParent.get_ref(mFieldName, array{})); }
        inline const array& get_ref_to_array() const { return std::get<array>(mParent.get_ref(mFieldName, array{})); }
        inline size_t size() const { return get_ref_to_array().size(); }
        inline bool empty() const { return get_ref_to_array().empty(); }
        inline iterator begin() const { return get_ref_to_array().begin(); }
        inline iterator end() const { return get_ref_to_array().end(); }
        inline iterator begin() { return get_ref_to_array().begin(); }
        inline iterator end() { return get_ref_to_array().end(); }

        inline Element emplace_back()
            {
                auto& ar = get_ref_to_array();
                ar.insert(object{});
                return Element{*ar.rbegin()};
            }

     private:
        field_container_parent& mParent;
        std::string mFieldName;

    }; // class array_field_container_child<>

    class array_field_container_child_element : public field_container_parent
    {
     public:
        inline array_field_container_child_element(const value& aData) : mData{aData} {}

        inline value& get_ref(std::string aFieldName, value&& aDefault) override { return const_cast<value&>(mData).get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline const value& get_ref(std::string aFieldName, value&& aDefault) const override { return const_cast<value&>(mData).get_ref(aFieldName, std::forward<value>(aDefault)); }
        inline object& get_ref_to_object(std::string aFieldName) override { return const_cast<value&>(mData).get_ref_to_object(aFieldName); }
        inline void set_field(std::string aFieldName, value&& aValue) override { const_cast<value&>(mData).set_field(aFieldName, std::forward<value>(aValue)); }

     private:
        const value& mData;
    };

      // ----------------------------------------------------------------------

    template <typename FValue> class field_get_set
    {
     public:
        inline field_get_set(field_container_parent& aParent, std::string aFieldName, FValue&& aDefault) : mParent{aParent}, mFieldName{aFieldName}, mDefault{std::move(aDefault)} {}
        inline field_get_set(field_container_parent& aParent, std::string aFieldName, const FValue& aDefault) : mParent{aParent}, mFieldName{aFieldName}, mDefault{aDefault} {}

        inline const rjson_type<FValue>& get_value_ref() const
            {
                try {
                    return std::get<rjson_type<FValue>>(get_ref());
                }
                catch (std::bad_variant_access& /*err*/) {
                    std::cerr << "ERROR: cannot convert json to " <<  typeid(rjson_type<FValue>).name() << " (" << typeid(FValue).name() << "): " << get_ref() << '\n';
                    throw;
                }
            }

          // inline field_get_set<FValue>& operator = (FValue&& aValue) { mParent.set_field(mFieldName, to_value(aValue)); return *this; }
        inline field_get_set<FValue>& operator = (const FValue& aValue) { mParent.set_field(mFieldName, to_value(aValue)); return *this; }
        inline field_get_set<FValue>& operator = (const field_get_set<FValue>& aSource) { return operator=(static_cast<FValue>(aSource)); }

        inline bool empty() const { return static_cast<FValue>(*this).empty(); }

          // to be specialized for complex types
        inline operator FValue() const { return get_value_ref(); }

     private:
        field_container_parent& mParent;
        std::string mFieldName;
        FValue mDefault;

        // inline value& get_ref() { return mParent.get_ref(mFieldName, to_value(mDefault)); }
        inline const value& get_ref() const { return mParent.get_ref(mFieldName, to_value(mDefault)); }
        // inline rjson_type<FValue>& get_value_ref() { return std::get<rjson_type<FValue>>(get_ref()); }

    }; // class field_get_set<>

      // ----------------------------------------------------------------------
      // double: can be extracted from rjson::number and rjson::integer
      // ----------------------------------------------------------------------

    template <> inline field_get_set<double>::operator double() const
    {
        if (auto ptr_n = std::get_if<number>(&get_ref()))
            return *ptr_n;
        else if (auto ptr_i = std::get_if<integer>(&get_ref()))
            return *ptr_i;
        else {
            std::cerr << "ERROR: cannot convert json to double (from rjson::number or rjson::integer): " << get_ref() << '\n';
            throw std::bad_variant_access{};
        }
    }

      // ----------------------------------------------------------------------
      // Color
      // ----------------------------------------------------------------------

    template <> struct content_type<Color> { using type = string; };

    template <> inline field_get_set<Color>::operator Color() const { return static_cast<std::string>(get_value_ref()); }

      // ----------------------------------------------------------------------
      // Size
      // ----------------------------------------------------------------------

    template <> struct content_type<Size> { using type = array; };

    template <> inline field_get_set<Size>::operator Size() const
    {
        const auto& ar = get_value_ref(); // std::get<array>(get_ref());
        return {std::get<number>(ar[0]), std::get<number>(ar[1])};
    }

    template <> inline value to_value<Size>(const Size& aSize)
    {
        return array{number{aSize.width}, number{aSize.height}};
    }

      // ----------------------------------------------------------------------
      // TextStyle
      // ----------------------------------------------------------------------

    template <> struct content_type<TextStyle> { using type = object; };

    template <> inline field_get_set<TextStyle>::operator TextStyle() const
    {
        const auto& obj = get_value_ref(); // std::get<object>(get_ref());
        TextStyle style;
        try { style.font_family(obj.get_field<std::string>("family")); } catch (object::field_not_found&) {}
        try { style.slant(obj.get_field<std::string>("slant")); } catch (object::field_not_found&) {}
        try { style.weight(obj.get_field<std::string>("weight")); } catch (object::field_not_found&) {}
        return style;
    }

    template <> inline value to_value<TextStyle>(const TextStyle& aTextStyle)
    {
        return object{
            {"family", string{aTextStyle.font_family()}},
            {"slant", string{aTextStyle.slant_as_stirng()}},
            {"weight", string{aTextStyle.weight_as_stirng()}}
        };
    }

      // ----------------------------------------------------------------------
      // std::vector<std::string>
      // ----------------------------------------------------------------------

    template <> struct content_type<std::vector<std::string>> { using type = array; };

    template <> inline field_get_set<std::vector<std::string>>::operator std::vector<std::string>() const
    {
        const auto& ar = get_value_ref();
        std::vector<std::string> result{ar.size()};
        std::transform(ar.begin(), ar.end(), result.begin(), [](const rjson::value& elt) -> std::string { return std::get<rjson::string>(elt); });
        return result;
    }

    template <> inline value to_value<std::vector<std::string>>(const std::vector<std::string>& aData)
    {
        array ar;
        for (const auto& elt: aData)
            ar.insert(string{elt});
        return ar;
    }

} // namespace rjson

// ----------------------------------------------------------------------

template <typename FValue> inline std::ostream& operator<<(std::ostream& out, const rjson::field_get_set<FValue>& aValue)
{
    return out << static_cast<FValue>(aValue);
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>