lib/eth/rlp/sedes/binary.rb

Summary

Maintainability
A
0 mins
Test Coverage
# Copyright (c) 2016-2023 The Ruby-Eth Contributors
#
# 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.

# -*- encoding : ascii-8bit -*-

# Provides the {Eth} module.
module Eth

  # Provides an recursive-length prefix (RLP) encoder and decoder.
  module Rlp

    # Provides serializable and deserializable types (SeDes).
    module Sedes

      # A sedes type for binary values.
      class Binary

        # A singleton class for binary values of fixed length.
        class << self

          # Create a serializable binary of fixed size.
          #
          # @param l [Integer] the fixed size of the binary.
          # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
          # @return [Eth::Rlp::Sedes::Binary] a serializable binary of fixed size.
          def fixed_length(l, allow_empty: false)
            new(min_length: l, max_length: l, allow_empty: allow_empty)
          end

          # Checks wether the given object is of a valid binary type.
          #
          # @param obj [Object] the supposed binary item to check.
          # @return [Boolean] true if valid.
          def valid_type?(obj)
            obj.instance_of? String
          end
        end

        # Create a serializable binary of variable size.
        #
        # @param min_length [Integer] the minimum size of the binary.
        # @param max_length [Integer] the maximum size of the binary.
        # @param allow_empty [Boolean] indicator wether empty binaries should be allowed.
        def initialize(min_length: 0, max_length: Constant::INFINITY, allow_empty: false)
          @min_length = min_length
          @max_length = max_length
          @allow_empty = allow_empty
        end

        # Serializes a binary.
        #
        # @param obj [String] the binary to serialize.
        # @return [Object] a serialized binary.
        # @raise [SerializationError] if provided object is of invalid type.
        # @raise [SerializationError] if provided binary is of invalid length.
        def serialize(obj)
          raise SerializationError, "Object is not a serializable (#{obj.class})" unless self.class.valid_type? obj
          serial = Util.str_to_bytes obj
          raise SerializationError, "Object has invalid length" unless valid_length? serial.size
          serial
        end

        # Deserializes a binary.
        #
        # @param serial [Object] the serialized binary.
        # @return [String] a deserialized binary.
        # @raise [DeserializationError] if provided serial is of wrong type.
        # @raise [DeserializationError] if provided serial is of wrong length.
        def deserialize(serial)
          raise DeserializationError, "Objects of type #{serial.class} cannot be deserialized" unless Util.primitive? serial
          raise DeserializationError, "#{serial.class} has invalid length" unless valid_length? serial.size
          serial
        end

        # Checks wether the given length fits the defined size boundaries of the
        # binary type.
        #
        # @param length [Integer] the supposed length of the binary item.
        # @return [Boolean] true if valid.
        def valid_length?(length)
          (@min_length <= length && length <= @max_length) || (@allow_empty && length == 0)
        end
      end
    end
  end
end