Какие типы могут быть отображены в TLV?

Какие правила и ограничения существуют для наследования?

Допускается ли множественное наследование?

Как быть, если в базовом и производном типах есть атрибуты, являющиеся одним и тем же TLV?

Как быть, если атрибут является указателем, но должен быть обязательным? Или наоборот: атрибут не является указателем и не является обязательным атрибутом?

Как быть с абстрактными типами?

Как описывать отображение схемы данных в TLV.

Правила отображения схемы данных в TLV.

Что получается в результате трансляции описания отображения схемы данных в TLV?

Сериализованным в TLV может быть только тип, содержимое которого принадлежит к одному из следующих случаев:

- Тип не имеет собственных атрибутов (пустой тип).

- Атрибутами типа являтся скаляры простейших атомарных типов (char, uchar, schar, short, ushort, int, uint, float, double) или фиксированные вектора простейших атомарных типов.

  В этом случае все атрибуты типа должны присутствовать в сериализованном потоке и порядок следования атрибутов должен точно повторять порядок следования атрибутов в DDL-описании типа.

  Пример.

      {type	tlv_rnd_t
      	{attr	m_rnd	{of	oess_1::uint_t}}
      }

      {type	tlv_date_t
      	{attr	m_year	{of	oess_1::ushort_t}}
      	{attr	m_mon	{of	oess_1::uchar_t}}
      	{attr	m_day	{of	oess_1::uchar_t}}
      }

      {type	tlv_des_params_t
      	{attr	m_des_type	{of	oess_1::uint_t}}
      	{attr	m_des_key
      		{fixed-vector	8}
      		{of	oess_1::uchar_t}}
      }

- Единственным атрибутом типа является контейнер переменного размера (std::string, stl::vector, stl::list, stl::deque, stl::set, std::multiset). Тип элемента контейнера не может быть контейнером (т.е. нельзя объявить stl::list из std::string).

  Размерность контейнера вычисляется на основе Length из TLV. (Алгоритм вычисления может быть и не тривиальным. Например, для строки Length сразу указывает количество элементов. Если элементом контейнера является объект фиксированного размера, то из Length так же легко вычислить количество элементов. В остальных случаях количество элементов из Length не вычисляется -- Length может использоваться как показатель конца потока, из которого последовательно считываются элементы.)

  Важно. Контейнеры map и multimap не могут быть сериализованы в TLV.

  Пример.

      {type	tlv_msisdn_t
      	{attr	m_msisdn	{of	std::string}}
      }

      {type	hilevel_tlv_t
      }

      {type	tlv_container_t
      	{attr	m_tlvs
      		{std::list}
      		{of {ptr}	hilevel_tlv_t}}
      }

- Тип состоит только из одиночных атрибутов пользовательских типов. Использование контейнеров не допускается.

  Атрибуты в сериализованном потоке могут следовать в любом порядке. Обязательно в сериализованном потоке должны присутствовать атрибуты, не являющиеся указателями. Атрибуты-указатели рассматриваются как необязательные атрибуты, которые могут отсутствовать в сериализованном потоке.

  Пример.

      {type	tlv_user_status_request_t
      	{attr	m_rnd	{of	tlv_rnd_t}}
      	{attr	m_msisdn	{of	tlv_msisdn_t}}
      }

      {type	tlv_user_status_reply_t
      	{attr	m_rnd	{of	tlv_rnd_t}}
      	{attr	m_bank_status	{of	tlv_bank_status_t}}
      	{attr	m_user_status	{of {ptr}	tlv_user_status_t}}
      	{attr	m_card_names	{of {ptr}	tlv_card_names_t}}
      }

      {type	tlv_card_names_t
      	{attr	m_names
      		{std::list}
      		{of tlv_card_name_t}}
      }

Т.о. получаются следующие категории отображаемых в TLV типов:

empty
  Пустой тип.
primitive
  Атрибутами являются только примитивные объекты или фиксированные вектора примитивных объектов.
complex
  Атрибутами являются одиночные объекты определенных пользователем типов.
container
  Единственный атрибут - контейнер. Элементом контейнера может быть одиночный объект либо примитивного, либо пользовательского типа.

Наследование возможно, если категории базовых и производных типов соотносятся следующим образом (указывается категория базового типа и допустимые категории производных типов, в скобках отмечается категория результирующего типа):

empty
  empty (empty), primitive (primitive), complex (complex), container (container);
primitive
  empty (primitive), primitive (primitive);
complex
  complex (complex);
container
  empty (container).

Множественное наследование не допускается.

Возможно, в дальнейшем, ситуация с множественным наследованием изменится. Пока проектирование множественного наследования для отображения в TLV является слишком трудоемким.

Для абстрактного типа нельзя назначить значение Tag. В остальном ситуация с абстрактными типами остается такой же, как с другими базовыми типами.

При наследовании в базовых и производных классах не должно быть атрибутов, отображаемых в один и тот же TLV. Для атрибутов не указателей это означает, что в базовом и производном типе не должно быть атрибутов, имеющих один и тот же пользовательский тип. Для атрибутов-указателей это означает, что в базовом и производном типе не должно быть атрибутов, тип которых относится к одному семейству классов. Под семейством понимаются классы, имеющих общего предка.

Не реализовано. Оставлено для будующих реализаций.
Чтобы объявить атрибут-указатель обязательным атрибутом необходимо использовать специальные теги в описании отображения типа:

    {type имя-типа
    	{mandatory-attr имя-обязательного-атрибута}
    }

Объявить атрибут-не указатель необязательным атрибутом нельзя. Объясняется это тем, что при сериализации нельзя определить, должен ли сериализироваться необязательный атрибут или не должен.

Для отображения схемы данных в TLV необходимо создать описание отображения следующего формата.

    {tlv-params
    	{tag-type
    		( oess_1::uchar_t |
    		  oess_1::ushort_t |
    		  oess_1::uint_t ) }

    	{length-type
    		( oess_1::uchar_t |
    		  oess_1::ushort_t |
    		  oess_1::uint_t ) }

    	{i-class имя-класса-десериализатора
    		[{cpp-namespace имя-пространства-имен-C++}]
    	}
    	{o-class имя-класса-сериализатора
    		[{cpp-namespace имя-пространства-имен-C++}]
    	}
    }

    [ {type имя-типа-схемы
    	{tag целочисленное-значение }
    } ]*

Примеры:
mobilling
smsg

Для отображаемых в TLV типов существуют следующие ограничения:

- Быть сериализованными в TLV могут быть типы, которым было назначено значение Tag.
- Атрибутами сериализуемых в TLV типов могут быть либо объекты примитивных типов, либо объекты типов, которым назначено значение Tag.
- Значениями атрибутов-указателей сериализуемых в TLV типов могут быть только объекты типов, которым назначено значение Tag.

Результатом трансляции описания отображения схемы данных в TLV являются два C++ класса: один для сериализации, другой для десериализации сущности. Имена классов задаются в описании отображения (теги i-class и o-class).

Для сериализации/десериализации объектов в/из TLV должны применяться объекты сгенерированных классов. Например, если в tlv-map указывается:

    {tlv-params
    	{tag-type	oess_1::uchar_t}
    	{length-type	oess_1::uint_t}

    	{i-class	itlv_t }
    	{o-class	otlv_t }
    }

То в программе на C++:

    // Сериализация объекта.
    tlv_my_t my_tlv;
    otlv_t oent( ... );
    oent << my_tlv;

    // Десериализация объекта.
    tlv_my_t my_tlv;
    itlv_t ient( ... );
    ient >> my_tlv;