# frozen_string_literal: true

# This file is part of RASN1
# See https://codeberg.org/lemontree55/rasn1 for more informations
# Copyright (C) 2016-2024 Sylvain Daubert <sylvain.daubert@laposte.net>
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
# This program is published under MIT license.

module RASN1
  module Types
    # Mixin to add constraints on a RASN1 type.
    # Should not be used directly but through {Types.define_type}.
    # @version 0.11.0
    # @author Sylvain Daubert
    module Constrained
      # Define class/module methods for {Constrained} module
      module ClassMethods
        # @return [Proc] proc to check constraints
        attr_accessor :constraint

        # Check if a constraint is really defined
        # @return [Boolean]
        def constrained?
          @constraint.is_a?(Proc)
        end

        # Check constraint, if defined
        # @param value [Object] the value of the type to check
        # @raise [ConstraintError] constraint is not verified
        def check_constraint(value)
          return unless constrained?
          raise ConstraintError.new(self) unless @constraint.call(value)
        end
      end

      extend ClassMethods

      # Redefined +#value=+ to check constraint before assigning +val+
      # @!macro value_setter
      # @see Types::Base#value=
      # @raise [ConstraintError] constraint is not verified
      def value=(val)
        self.class.check_constraint(val)
        super
      end

      # Make value from +der+ string and check constraints
      # @param der [String]
      # @param ber [::Boolean]
      # @return [void]
      # @raise [ConstraintError] constraint is not verified
      def der_to_value(der, ber: false)
        super
        self.class.check_constraint(@value)
      end
    end
  end
end
