Class: Twilic::Core::Protocol::SessionEncoder

Inherits:
Object
  • Object
show all
Defined in:
lib/twilic/core/protocol.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ SessionEncoder

Returns a new instance of SessionEncoder.



1620
1621
1622
# File 'lib/twilic/core/protocol.rb', line 1620

def initialize(options)
  @codec = Protocol.twilic_codec_with_options(options)
end

Instance Attribute Details

#codecObject (readonly)

Returns the value of attribute codec.



1618
1619
1620
# File 'lib/twilic/core/protocol.rb', line 1618

def codec
  @codec
end

Instance Method Details

#decode_message(bytes) ⇒ Object



1775
1776
1777
# File 'lib/twilic/core/protocol.rb', line 1775

def decode_message(bytes)
  codec.decode_message(bytes)
end

#encode(value) ⇒ Object



1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
# File 'lib/twilic/core/protocol.rb', line 1624

def encode(value)
  msg = codec.message_for_value(value)
  if codec.state.options.enable_state_patch && codec.state.previous_message &&
     supports_state_patch(codec.state.previous_message, msg)
    base_ref = Model::BaseRef.previous
    ops, _literals = diff_message(codec.state.previous_message, msg)
    patch_msg = Model.message(
      kind: Model::MessageKind::STATE_PATCH,
      state_patch: Model::StatePatchMessage.new(base_ref: base_ref, operations: ops, literals: [])
    )
    patch_size = encoded_size(patch_msg)
    full_size = encoded_size(msg)
    if patch_size < full_size
      begin
        return codec.encode_message(patch_msg)
      rescue StandardError
        # fall back to full message path
      end
    end
  end
  codec.encode_message(msg)
end

#encode_batch(values) ⇒ Object



1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
# File 'lib/twilic/core/protocol.rb', line 1679

def encode_batch(values)
  if values.empty?
    msg = Model.message(
      kind: Model::MessageKind::ROW_BATCH,
      row_batch: Model::RowBatchMessage.new(rows: [])
    )
    return codec.encode_message(msg)
  end

  msg = nil
  if values.length >= 16
    cols = columns_from_map_values(values)
    cols = rows_to_columns(rows_from_values(values)) if cols.nil?
    Dictionary.apply_dictionary_references(codec.state, cols) if codec.state.options.enable_trained_dictionary
    msg = Model.message(
      kind: Model::MessageKind::COLUMN_BATCH,
      column_batch: Model::ColumnBatchMessage.new(count: values.length, columns: cols)
    )
  else
    msg = Model.message(
      kind: Model::MessageKind::ROW_BATCH,
      row_batch: Model::RowBatchMessage.new(rows: rows_from_values(values))
    )
  end

  bytes = codec.encode_message(msg)
  codec.state.previous_message = msg
  size = bytes.bytesize
  codec.state.previous_message_size = size
  record_full_message_as_base
  bytes
end

#encode_micro_batch(values) ⇒ Object



1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
# File 'lib/twilic/core/protocol.rb', line 1737

def encode_micro_batch(values)
  return encode_batch(values) if values.empty?
  if !codec.state.options.enable_template_batch || !has_uniform_micro_batch_shape(values)
    return encode_batch(values)
  end

  columns = columns_from_map_values(values)
  columns = rows_to_columns(rows_from_values(values)) if columns.nil?
  Dictionary.apply_dictionary_references(codec.state, columns) if codec.state.options.enable_trained_dictionary
  template_id, ok = find_template_id(codec.state.templates, columns)
  unless ok
    template_id = codec.state.allocate_template_id
    codec.state.templates[template_id] = template_descriptor_from_columns(template_id, columns)
    codec.state.template_columns[template_id] = columns
    mask = Array.new(columns.length, true)
    msg = Model.message(
      kind: Model::MessageKind::TEMPLATE_BATCH,
      template_batch: Model::TemplateBatchMessage.new(
        template_id: template_id, count: values.length, changed_column_mask: mask, columns: columns
      )
    )
    return codec.encode_message(msg)
  end
  mask, changed_cols = diff_template_columns(codec.state.template_columns[template_id], columns)
  codec.state.template_columns[template_id] = columns
  msg = Model.message(
    kind: Model::MessageKind::TEMPLATE_BATCH,
    template_batch: Model::TemplateBatchMessage.new(
      template_id: template_id, count: values.length, changed_column_mask: mask, columns: changed_cols
    )
  )
  codec.encode_message(msg)
end

#encode_patch(value) ⇒ Object



1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
# File 'lib/twilic/core/protocol.rb', line 1720

def encode_patch(value)
  msg = codec.message_for_value(value)
  if codec.state.previous_message.nil? || !supports_state_patch(codec.state.previous_message, msg)
    return codec.encode_message(msg)
  end
  ops, _literals = diff_message(codec.state.previous_message, msg)
  patch_msg = Model.message(
    kind: Model::MessageKind::STATE_PATCH,
    state_patch: Model::StatePatchMessage.new(
      base_ref: Model::BaseRef.previous, operations: ops, literals: []
    )
  )
  return codec.encode_message(msg) if encoded_size(patch_msg) >= encoded_size(msg)

  codec.encode_message(patch_msg)
end

#encode_with_schema(schema, value) ⇒ Object



1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
# File 'lib/twilic/core/protocol.rb', line 1647

def encode_with_schema(schema, value)
  codec.state.schemas[schema.schema_id] = schema
  codec.state.last_schema_id = schema.schema_id
  schema.fields.each do |field|
    next if field.enum_values.empty?

    codec.state.field_enums[field.name] = field.enum_values.dup
  end
  raise Errors.invalid_data("encode_with_schema expects map value") unless value.kind == Model::ValueKind::MAP

  presence = Array.new(schema.fields.length, false)
  fields = []
  has_presence = false
  schema.fields.each_with_index do |field, i|
    v = lookup_map_field(value, field.name)
    if v
      presence[i] = true
      fields << v.clone_value
    else
      presence[i] = false
      has_presence = true
    end
  end
  msg = Model.message(
    kind: Model::MessageKind::SCHEMA_OBJECT,
    schema_object: Model::SchemaObjectMessage.new(
      schema_id: schema.schema_id, presence: presence, has_presence: has_presence, fields: fields
    )
  )
  codec.encode_message(msg)
end

#record_full_message_as_baseObject



1712
1713
1714
1715
1716
1717
1718
# File 'lib/twilic/core/protocol.rb', line 1712

def record_full_message_as_base
  return if codec.state.options.max_base_snapshots.zero?
  return if codec.state.previous_message.nil?

  base_id = codec.state.allocate_base_id
  codec.state.register_base_snapshot(base_id, codec.state.previous_message)
end

#resetObject



1771
1772
1773
# File 'lib/twilic/core/protocol.rb', line 1771

def reset
  codec.state.reset_state
end