ChaiScript / ChaiScript
1
// This file is distributed under the BSD License.
2
// See "license.txt" for details.
3
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
4
// Copyright 2009-2018, Jason Turner (jason@emptycrate.com)
5
// http://www.chaiscript.com
6

7
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
8
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
9

10

11
#ifndef CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
12
#define CHAISCRIPT_DYNAMIC_CAST_CONVERSION_HPP_
13

14
#include <atomic>
15
#include <memory>
16
#include <set>
17
#include <stdexcept>
18
#include <string>
19
#include <type_traits>
20
#include <typeinfo>
21

22
#include "../chaiscript_threading.hpp"
23
#include "../utility/static_string.hpp"
24
#include "bad_boxed_cast.hpp"
25
#include "boxed_cast_helper.hpp"
26
#include "boxed_value.hpp"
27
#include "type_info.hpp"
28

29
namespace chaiscript
30
{
31
  namespace exception
32
  {
33
    /// \brief Error thrown when there's a problem with type conversion
34
    class conversion_error: public bad_boxed_cast
35
    {
36
       public:
37 1
         conversion_error(const Type_Info t_to, const Type_Info t_from, const utility::Static_String what) noexcept
38 1
         : bad_boxed_cast(t_from, (*t_to.bare_type_info()), what), type_to(t_to) {};
39

40
        Type_Info type_to;
41
    };
42

43
    class bad_boxed_dynamic_cast : public bad_boxed_cast
44
    {
45
      public:
46 1
        bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to,
47
            const utility::Static_String &t_what) noexcept
48 1
          : bad_boxed_cast(t_from, t_to, t_what)
49
        {
50
        }
51

52
        bad_boxed_dynamic_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
53
          : bad_boxed_cast(t_from, t_to)
54
        {
55
        }
56

57
        explicit bad_boxed_dynamic_cast(const utility::Static_String &w) noexcept
58
          : bad_boxed_cast(w)
59
        {
60
        }
61

62
        bad_boxed_dynamic_cast(const bad_boxed_dynamic_cast &) = default;
63

64 1
        ~bad_boxed_dynamic_cast() noexcept override = default;
65
    };
66

67
    class bad_boxed_type_cast : public bad_boxed_cast
68
    {
69
      public:
70
        bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to,
71
            const utility::Static_String &t_what) noexcept
72
          : bad_boxed_cast(t_from, t_to, t_what)
73
        {
74
        }
75

76
        bad_boxed_type_cast(const Type_Info &t_from, const std::type_info &t_to) noexcept
77
          : bad_boxed_cast(t_from, t_to)
78
        {
79
        }
80

81 0
        explicit bad_boxed_type_cast(const utility::Static_String &w) noexcept
82 0
          : bad_boxed_cast(w)
83
        {
84
        }
85

86
        bad_boxed_type_cast(const bad_boxed_type_cast &) = default;
87

88 0
        ~bad_boxed_type_cast() noexcept override = default;
89
    };
90
  }
91

92

93
  namespace detail
94
  {
95
    class Type_Conversion_Base
96
    {
97
      public:
98
        virtual Boxed_Value convert(const Boxed_Value &from) const = 0;
99
        virtual Boxed_Value convert_down(const Boxed_Value &to) const = 0;
100

101 1
        const Type_Info &to() const noexcept
102
        {
103 1
          return m_to;
104
        }
105 1
        const Type_Info &from() const noexcept
106
        {
107 1
          return m_from;
108
        }
109

110 1
        virtual bool bidir() const noexcept
111
        {
112 1
          return true;
113
        }
114

115 1
        virtual ~Type_Conversion_Base() = default;
116

117
      protected:
118 1
        Type_Conversion_Base(Type_Info t_to, Type_Info t_from)
119 1
          : m_to(std::move(t_to)), m_from(std::move(t_from))
120
        {
121
        }
122

123

124
      private:
125
        const Type_Info m_to;
126
        const Type_Info m_from;
127

128
    };
129

130
    template<typename From, typename To> 
131
      class Static_Caster
132
      {
133
        public: 
134 1
          static Boxed_Value cast(const Boxed_Value &t_from)
135
          {
136

137 1
            if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
138
            {
139 1
              if (t_from.is_pointer())
140
              {
141
                // Dynamic cast out the contained boxed value, which we know is the type we want
142 1
                if (t_from.is_const())
143
                {
144
                  return Boxed_Value(
145 0
                      [&](){
146 0
                        if (auto data = std::static_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
147
                        {
148 0
                          return data;
149
                        } else {
150 0
                          throw std::bad_cast();
151
                        }
152 0
                      }()
153 0
                      );
154
                } else {
155
                  return Boxed_Value(
156
                      [&](){
157
                        if (auto data = std::static_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
158
                        {
159
                          return data;
160
                        } else {
161 0
                          throw std::bad_cast();
162
                        }
163
                      }()
164 1
                      );
165
                }
166
              } else {
167
                // Pull the reference out of the contained boxed value, which we know is the type we want
168 1
                if (t_from.is_const())
169
                {
170 1
                  const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
171 1
                  const To &data = static_cast<const To &>(d);
172 1
                  return Boxed_Value(std::cref(data));
173
                } else {
174 1
                  From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
175 1
                  To &data = static_cast<To &>(d);
176 1
                  return Boxed_Value(std::ref(data));
177
                }
178
              }
179
            } else {
180 0
              throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
181
            }
182
          }
183
 
184
      };
185

186

187
    template<typename From, typename To> 
188
      class Dynamic_Caster
189
      {
190
        public: 
191 1
          static Boxed_Value cast(const Boxed_Value &t_from)
192
          {
193 1
            if (t_from.get_type_info().bare_equal(chaiscript::user_type<From>()))
194
            {
195 1
              if (t_from.is_pointer())
196
              {
197
                // Dynamic cast out the contained boxed value, which we know is the type we want
198 1
                if (t_from.is_const())
199
                {
200
                  return Boxed_Value(
201 0
                      [&](){
202 0
                        if (auto data = std::dynamic_pointer_cast<const To>(detail::Cast_Helper<std::shared_ptr<const From> >::cast(t_from, nullptr)))
203
                        {
204 0
                          return data;
205
                        } else {
206 0
                          throw std::bad_cast();
207
                        }
208 0
                      }()
209 0
                      );
210
                } else {
211
                  return Boxed_Value(
212
                      [&](){
213
                        if (auto data = std::dynamic_pointer_cast<To>(detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr)))
214
                        {
215
                          return data;
216
                        } else {
217
#ifdef CHAISCRIPT_LIBCPP
218
                          /// \todo fix this someday after libc++ is fixed.
219
                          if (std::string(typeid(To).name()).find("Assignable_Proxy_Function") != std::string::npos) {
220
                            auto from = detail::Cast_Helper<std::shared_ptr<From> >::cast(t_from, nullptr);
221
                            if (std::string(typeid(*from).name()).find("Assignable_Proxy_Function_Impl") != std::string::npos) {
222
                              return std::static_pointer_cast<To>(from);
223
                            }
224
                          }
225
#endif
226
                          throw std::bad_cast();
227
                        }
228
                      }()
229 1
                      );
230
                }
231
              } else {
232
                // Pull the reference out of the contained boxed value, which we know is the type we want
233 1
                if (t_from.is_const())
234
                {
235 1
                  const From &d = detail::Cast_Helper<const From &>::cast(t_from, nullptr);
236 0
                  const To &data = dynamic_cast<const To &>(d);
237 1
                  return Boxed_Value(std::cref(data));
238
                } else {
239 0
                  From &d = detail::Cast_Helper<From &>::cast(t_from, nullptr);
240 0
                  To &data = dynamic_cast<To &>(d);
241 0
                  return Boxed_Value(std::ref(data));
242
                }
243
              }
244
            } else {
245 0
              throw chaiscript::exception::bad_boxed_dynamic_cast(t_from.get_type_info(), typeid(To), "Unknown dynamic_cast_conversion");
246
            }
247
          }
248
 
249
      };
250

251

252
    template<typename Base, typename Derived>
253
      class Dynamic_Conversion_Impl : public Type_Conversion_Base
254
    {
255
      public:
256 1
        Dynamic_Conversion_Impl()
257 1
          : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
258
        {
259
        }
260

261 1
        Boxed_Value convert_down(const Boxed_Value &t_base) const override
262
        {
263 1
          return Dynamic_Caster<Base, Derived>::cast(t_base);
264
        }
265

266 1
        Boxed_Value convert(const Boxed_Value &t_derived) const override
267
        {
268 1
          return Static_Caster<Derived, Base>::cast(t_derived);
269
        }
270
    };
271

272
    template<typename Base, typename Derived>
273
      class Static_Conversion_Impl : public Type_Conversion_Base
274
    {
275
      public:
276 1
        Static_Conversion_Impl()
277 1
          : Type_Conversion_Base(chaiscript::user_type<Base>(), chaiscript::user_type<Derived>())
278
        {
279
        }
280

281 0
        Boxed_Value convert_down(const Boxed_Value &t_base) const override
282
        {
283 0
          throw chaiscript::exception::bad_boxed_dynamic_cast(t_base.get_type_info(), typeid(Derived), 
284 0
              "Unable to cast down inheritance hierarchy with non-polymorphic types");
285
        }
286

287 0
        bool bidir() const noexcept override
288
        {
289 0
          return false;
290
        }
291

292 1
        Boxed_Value convert(const Boxed_Value &t_derived) const override
293
        {
294 1
          return Static_Caster<Derived, Base>::cast(t_derived);
295
        }
296
    };
297

298

299

300
    template<typename Callable>
301
    class Type_Conversion_Impl : public Type_Conversion_Base
302
    {
303
      public:
304 1
        Type_Conversion_Impl(Type_Info t_from, Type_Info t_to, Callable t_func)
305
          : Type_Conversion_Base(t_to, t_from),
306 1
            m_func(std::move(t_func))
307
        {
308
        }
309

310 0
        Boxed_Value convert_down(const Boxed_Value &) const override
311
        {
312 0
          throw chaiscript::exception::bad_boxed_type_cast("No conversion exists");
313
        }
314

315 1
        Boxed_Value convert(const Boxed_Value &t_from) const override
316
        {
317
          /// \todo better handling of errors from the conversion function
318 1
          return m_func(t_from);
319
        }
320

321 1
        bool bidir() const noexcept override
322
        {
323 1
          return false;
324
        }
325

326

327
      private:
328
        Callable m_func;
329
    };
330
  }
331

332
  class Type_Conversions
333
  {
334
    public:
335
      struct Conversion_Saves
336
      {
337
        bool enabled = false;
338
        std::vector<Boxed_Value> saves;
339
      };
340

341
      struct Less_Than
342
      {
343 1
        bool operator()(const std::type_info *t_lhs, const std::type_info *t_rhs) const noexcept
344
        {
345 1
          return *t_lhs != *t_rhs && t_lhs->before(*t_rhs);
346
        }
347
      };
348

349 1
      Type_Conversions()
350 1
        : m_mutex(),
351
          m_conversions(),
352
          m_convertableTypes(),
353 1
          m_num_types(0)
354
      {
355
      }
356

357
      Type_Conversions(const Type_Conversions &t_other) = delete;
358
      Type_Conversions(Type_Conversions &&) = default;
359

360
      Type_Conversions &operator=(const Type_Conversions &) = delete;
361
      Type_Conversions &operator=(Type_Conversions &&) = default;
362

363 1
      const std::set<const std::type_info *, Less_Than> &thread_cache() const
364
      {
365 1
        auto &cache = *m_thread_cache;
366 1
        if (cache.size() != m_num_types)
367
        {
368 1
          chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
369 1
          cache = m_convertableTypes;
370
        }
371

372 1
        return cache;
373
      }
374

375

376 1
      void add_conversion(const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
377
      {
378 1
        chaiscript::detail::threading::unique_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
379 1
        if (find_bidir(conversion->to(), conversion->from()) != m_conversions.end()) {
380 1
            throw exception::conversion_error(conversion->to(), conversion->from(),
381 1
                    "Trying to re-insert an existing conversion!");
382
        }
383 1
        m_conversions.insert(conversion);
384 1
        m_convertableTypes.insert({conversion->to().bare_type_info(), conversion->from().bare_type_info()});
385 1
        m_num_types = m_convertableTypes.size();
386
      }
387

388
      template<typename T>
389 1
        bool convertable_type() const noexcept
390
        {
391 1
          const auto type = user_type<T>().bare_type_info();
392 1
          return thread_cache().count(type) != 0;
393
        }
394

395
      template<typename To, typename From>
396
        bool converts() const noexcept
397
        {
398
          return converts(user_type<To>(), user_type<From>());
399
        }
400

401 1
      bool converts(const Type_Info &to, const Type_Info &from) const noexcept
402
      {
403 1
        const auto &types = thread_cache();
404 1
        if (types.count(to.bare_type_info()) != 0 && types.count(from.bare_type_info()) != 0)
405
        {
406 1
          return has_conversion(to, from);
407
        } else {
408 1
          return false;
409
        }
410
      }
411

412
      template<typename To>
413 1
        Boxed_Value boxed_type_conversion(Conversion_Saves &t_saves, const Boxed_Value &from) const
414
        {
415 1
          return boxed_type_conversion(user_type<To>(), t_saves, from);
416
        }
417

418
      template<typename From>
419 1
        Boxed_Value boxed_type_down_conversion(Conversion_Saves &t_saves, const Boxed_Value &to) const
420
        {
421 1
          return boxed_type_down_conversion(user_type<From>(), t_saves, to);
422
        }
423

424

425 1
        Boxed_Value boxed_type_conversion(const Type_Info &to, Conversion_Saves &t_saves, const Boxed_Value &from) const
426
        {
427
          try {
428 1
            Boxed_Value ret = get_conversion(to, from.get_type_info())->convert(from);
429 1
            if (t_saves.enabled) { t_saves.saves.push_back(ret); }
430 1
            return ret;
431 1
          } catch (const std::out_of_range &) {
432 1
            throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "No known conversion");
433 0
          } catch (const std::bad_cast &) {
434 0
            throw exception::bad_boxed_dynamic_cast(from.get_type_info(), *to.bare_type_info(), "Unable to perform dynamic_cast operation");
435
          }
436
        }
437

438 1
        Boxed_Value boxed_type_down_conversion(const Type_Info &from, Conversion_Saves &t_saves, const Boxed_Value &to) const
439
        {
440
          try {
441 1
            Boxed_Value ret = get_conversion(to.get_type_info(), from)->convert_down(to);
442 1
            if (t_saves.enabled) { t_saves.saves.push_back(ret); }
443 1
            return ret;
444 1
          } catch (const std::out_of_range &) {
445 1
            throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "No known conversion");
446 1
          } catch (const std::bad_cast &) {
447 1
            throw exception::bad_boxed_dynamic_cast(to.get_type_info(), *from.bare_type_info(), "Unable to perform dynamic_cast operation");
448
          }
449
        }
450

451 1
      static void enable_conversion_saves(Conversion_Saves &t_saves, bool t_val) 
452
      {
453 1
        t_saves.enabled = t_val;
454
      }
455

456 1
      std::vector<Boxed_Value> take_saves(Conversion_Saves &t_saves)
457
      {
458 1
        std::vector<Boxed_Value> ret;
459 1
        std::swap(ret, t_saves.saves);
460 1
        return ret;
461
      }
462

463 1
      bool has_conversion(const Type_Info &to, const Type_Info &from) const
464
      {
465 1
        chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
466 1
        return find_bidir(to, from) != m_conversions.end();
467
      }
468

469 1
      std::shared_ptr<detail::Type_Conversion_Base> get_conversion(const Type_Info &to, const Type_Info &from) const
470
      {
471 1
        chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
472

473 1
        const auto itr = find(to, from);
474

475 1
        if (itr != m_conversions.end())
476
        {
477 1
          return *itr;
478
        } else {
479 1
          throw std::out_of_range(std::string("No such conversion exists from ") + from.bare_name() + " to " + to.bare_name());
480
        }
481
      }
482

483 1
      Conversion_Saves &conversion_saves() const noexcept {
484 1
        return *m_conversion_saves;
485
      }
486

487
    private:
488 1
      std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find_bidir(
489
          const Type_Info &to, const Type_Info &from) const
490
      {
491
        return std::find_if(m_conversions.begin(), m_conversions.end(),
492
              [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion) -> bool
493
              {
494
                return  (conversion->to().bare_equal(to) && conversion->from().bare_equal(from))
495
                     || (conversion->bidir() && conversion->from().bare_equal(to) && conversion->to().bare_equal(from));
496
              }
497 1
        );
498
      }
499

500 1
      std::set<std::shared_ptr<detail::Type_Conversion_Base> >::const_iterator find(
501
          const Type_Info &to, const Type_Info &from) const
502
      {
503
        return std::find_if(m_conversions.begin(), m_conversions.end(),
504
              [&to, &from](const std::shared_ptr<detail::Type_Conversion_Base> &conversion)
505
              {
506
                return conversion->to().bare_equal(to) && conversion->from().bare_equal(from);
507
              }
508 1
        );
509
      }
510

511
      std::set<std::shared_ptr<detail::Type_Conversion_Base>> get_conversions() const
512
      {
513
        chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
514

515
        return m_conversions;
516
      }
517

518

519

520
      mutable chaiscript::detail::threading::shared_mutex m_mutex;
521
      std::set<std::shared_ptr<detail::Type_Conversion_Base>> m_conversions;
522
      std::set<const std::type_info *, Less_Than> m_convertableTypes;
523
      std::atomic_size_t m_num_types;
524
      mutable chaiscript::detail::threading::Thread_Storage<std::set<const std::type_info *, Less_Than>> m_thread_cache;
525
      mutable chaiscript::detail::threading::Thread_Storage<Conversion_Saves> m_conversion_saves;
526
  };
527

528
  class Type_Conversions_State
529
  {
530
    public:
531 1
      Type_Conversions_State(const Type_Conversions &t_conversions,
532
          Type_Conversions::Conversion_Saves &t_saves)
533 1
        : m_conversions(t_conversions),
534 1
          m_saves(t_saves)
535
      {
536
      }
537

538 1
      const Type_Conversions *operator->() const noexcept {
539 1
        return &m_conversions.get();
540
      }
541

542 1
      const Type_Conversions *get() const noexcept {
543 1
        return &m_conversions.get();
544
      }
545

546 1
      Type_Conversions::Conversion_Saves &saves() const noexcept {
547 1
        return m_saves;
548
      }
549

550
    private:
551
      std::reference_wrapper<const Type_Conversions> m_conversions;
552
      std::reference_wrapper<Type_Conversions::Conversion_Saves> m_saves;
553
  };
554

555
  using Type_Conversion = std::shared_ptr<chaiscript::detail::Type_Conversion_Base>;
556

557
  /// \brief Used to register a to / parent class relationship with ChaiScript. Necessary if you
558
  ///        want automatic conversions up your inheritance hierarchy.
559
  ///
560
  /// Create a new to class registration for applying to a module or to the ChaiScript engine
561
  /// Currently, due to limitations in module loading on Windows, and for the sake of portability,
562
  /// if you have a type that is introduced in a loadable module and is used by multiple modules
563
  /// (through a tertiary dll that is shared between the modules, static linking the new type
564
  /// into both loadable modules would not be portable), you need to register the type
565
  /// relationship in all modules that use the newly added type in a polymorphic way.
566
  ///
567
  /// Example:
568
  /// \code
569
  /// class Base
570
  /// {};
571
  /// class Derived : public Base
572
  /// {};
573
  ///
574
  /// chaiscript::ChaiScript chai;
575
  /// chai.add(chaiscript::to_class<Base, Derived>());
576
  /// \endcode
577
  /// 
578
  template<typename Base, typename Derived>
579 1
  Type_Conversion base_class()
580
  {
581
    //Can only be used with related polymorphic types
582
    //may be expanded some day to support conversions other than child -> parent
583
    static_assert(std::is_base_of<Base,Derived>::value, "Classes are not related by inheritance");
584

585
    if constexpr(std::is_polymorphic<Base>::value && std::is_polymorphic<Derived>::value) {
586 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Dynamic_Conversion_Impl<Base, Derived>>();
587
    } else {
588 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Static_Conversion_Impl<Base, Derived>>();
589
    }
590
  }
591

592

593
  template<typename Callable>
594 1
    Type_Conversion type_conversion(const Type_Info &t_from, const Type_Info &t_to, 
595
        const Callable &t_func)
596
    {
597 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<Callable>>(t_from, t_to, t_func);
598
    }
599

600
  template<typename From, typename To, typename Callable>
601 1
    Type_Conversion type_conversion(const Callable &t_function)
602
    {
603
      auto func = [t_function](const Boxed_Value &t_bv) -> Boxed_Value {
604
            // not even attempting to call boxed_cast so that we don't get caught in some call recursion
605
            return chaiscript::Boxed_Value(t_function(detail::Cast_Helper<const From &>::cast(t_bv, nullptr)));
606
          };
607

608 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
609
    }
610

611
  template<typename From, typename To>
612 1
    Type_Conversion type_conversion()
613
    {
614
      static_assert(std::is_convertible<From, To>::value, "Types are not automatically convertible");
615
      auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
616
            // not even attempting to call boxed_cast so that we don't get caught in some call recursion
617
            return chaiscript::Boxed_Value(To(detail::Cast_Helper<From>::cast(t_bv, nullptr)));
618
          };
619

620 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<From>(), user_type<To>(), func);
621
    }
622

623
  template<typename To>
624 1
    Type_Conversion vector_conversion()
625
    {
626
      auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
627
        const std::vector<Boxed_Value> &from_vec = detail::Cast_Helper<const std::vector<Boxed_Value> &>::cast(t_bv, nullptr);
628

629
        To vec;
630
        vec.reserve(from_vec.size());
631
        for (const Boxed_Value &bv : from_vec) {
632
          vec.push_back(detail::Cast_Helper<typename To::value_type>::cast(bv, nullptr));
633
        }
634

635
        return Boxed_Value(std::move(vec));
636
      };
637

638 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::vector<Boxed_Value>>(), user_type<To>(), func);
639
    }
640

641
  template<typename To>
642 1
    Type_Conversion map_conversion()
643
    {
644 1
      auto func = [](const Boxed_Value &t_bv) -> Boxed_Value {
645 1
        const std::map<std::string, Boxed_Value> &from_map = detail::Cast_Helper<const std::map<std::string, Boxed_Value> &>::cast(t_bv, nullptr);
646

647 1
        To map;
648 1
        for (const std::pair<std::string, Boxed_Value> &p : from_map) {
649 1
          map.insert(std::make_pair(p.first, detail::Cast_Helper<typename To::mapped_type>::cast(p.second, nullptr)));
650
        }
651

652 1
        return Boxed_Value(std::move(map));
653
      };
654

655 1
      return chaiscript::make_shared<detail::Type_Conversion_Base, detail::Type_Conversion_Impl<decltype(func)>>(user_type<std::map<std::string, Boxed_Value>>(), user_type<To>(), func);
656
    }
657
}
658

659

660
#endif

Read our documentation on viewing source code .

Loading