+.. _definedby:
+
+DEFINED BY
+----------
+
+ASN.1 structures often have ANY and OCTET STRING fields, that are
+DEFINED BY some previously met ObjectIdentifier. This library provides
+ability to specify mapping between some OID and field that must be
+decoded with specific specification.
+
+defines kwarg
+_____________
+
+:py:class:`pyderasn.ObjectIdentifier` field inside
+:py:class:`pyderasn.Sequence` can hold mapping between OIDs and
+necessary for decoding structrures. For example, CMS (:rfc:`5652`)
+container::
+
+ class ContentInfo(Sequence):
+ schema = (
+ ("contentType", ContentType(defines=("content", {
+ id_digestedData: DigestedData(),
+ id_signedData: SignedData(),
+ }))),
+ ("content", Any(expl=tag_ctxc(0))),
+ )
+
+``contentType`` field tells that it defines that ``content`` must be
+decoded with ``SignedData`` specification, if ``contentType`` equals to
+``id-signedData``. The same applies to ``DigestedData``. If
+``contentType`` contains unknown OID, then no automatic decoding is
+done.
+
+Following types can be automatically decoded (DEFINED BY):
+
+* :py:class:`pyderasn.Any`
+* :py:class:`pyderasn.OctetString`
+* :py:class:`pyderasn.SequenceOf`/:py:class:`pyderasn.SetOf`
+ ``Any``/``OctetString``-s
+
+When any of those fields is automatically decoded, then ``.defined``
+attribute contains ``(OID, value)`` tuple. OID tell by which OID it was
+defined, ``value`` contains corresponding decoded value. For example
+above, ``content_info["content"].defined == (id_signedData,
+signed_data)``.
+
+defines_by_path kwarg
+_____________________
+
+Sometimes you either can not or do not want to explicitly set *defines*
+in the scheme. You can dynamically apply those definitions when calling
+``.decode()`` method.
+
+Decode method takes optional ``defines_by_path`` keyword argument that
+must be sequence of following tuples::
+
+ (decode_path, defines)
+
+where ``decode_path`` is a tuple holding so-called decode path to the
+exact :py:class:`pyderasn.ObjectIdentifier` field you want to apply
+``defines``, holding exactly the same value as accepted in its keyword
+argument.
+
+For example, again for CMS, you want to automatically decode
+``SignedData`` and CMC's (:rfc:`5272`) ``PKIData`` and ``PKIResponse``
+structures it may hold. Also, automatically decode ``controlSequence``
+of ``PKIResponse``::
+
+ content_info, tail = ContentInfo().decode(data, defines_by_path=(
+ (
+ ("contentType",),
+ ("content", {id_signedData: SignedData()}),
+ ),
+ (
+ (
+ "content",
+ decode_path_defby(id_signedData),
+ "encapContentInfo",
+ "eContentType",
+ ),
+ ("eContent", {
+ id_cct_PKIData: PKIData(),
+ id_cct_PKIResponse: PKIResponse(),
+ }),
+ ),
+ (
+ (
+ "content",
+ decode_path_defby(id_signedData),
+ "encapContentInfo",
+ "eContent",
+ decode_path_defby(id_cct_PKIResponse),
+ "controlSequence",
+ any,
+ "attrType",
+ ),
+ ("attrValues", {
+ id_cmc_recipientNonce: RecipientNonce(),
+ id_cmc_senderNonce: SenderNonce(),
+ id_cmc_statusInfoV2: CMCStatusInfoV2(),
+ id_cmc_transactionId: TransactionId(),
+ }),
+ ),
+ ))
+
+Pay attention for :py:func:`pyderasn.decode_path_defby` and ``any``.
+First function is useful for path construction when some automatic
+decoding is already done. ``any`` is used for human readability and
+means literally any value it meet -- useful for sequence and set of-s.
+