123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openEncoding(* objs check that the same field doesn't appear twice *)moduleSSet=Set.Make(String)letsset_addnamefields=(ifSSet.memnamefieldsthenlets=Printf.sprintf"Data_encoding.objects: duplicate field name (%S)"nameinraise(Invalid_arguments));SSet.addnamefields(* This must traverse the constructors in the same fashion as `is_obj` *)letreccheck_dup_fields:typea.Mu_visited.t->SSet.t->at->SSet.t=funvisitedfieldsobjs->matchobjs.encodingwith|Obj(Req{name;_}|Opt{name;_}|Dft{name;_})->sset_addnamefields|Objs{left;right;_}->letfields=check_dup_fieldsvisitedfieldsleftinletfields=check_dup_fieldsvisitedfieldsrightinfields|Conv{encoding=e;_}->check_dup_fieldsvisitedfieldse|Dynamic_size{encoding=e;_}->check_dup_fieldsvisitedfieldse|Union{cases;_}->letfieldss=List.map(fun(Case{encoding=e;_})->check_dup_fieldsvisitedfieldse)casesinList.fold_leftSSet.unionfieldsfieldss|Empty->fields|Ignore->fields|Mu{fix;_}->assert(is_objobjs);ifMu_visited.memobjs.encodingvisitedthenfieldselsecheck_dup_fields(Mu_visited.addobjs.encodingvisited)fields(fixobjs)|Splitted{is_obj;_}->(* TL;DR: the only combinator for splitted sets [is_obj] at [false].
Long explanation:
The only combinator that can construct [Splitted] is
[Data_encoding.Encoding.splitted]. It is defined in
[src/data_encoding.ml] as a wrapper around [Encoding.raw_splitted] which sets
the field [is_obj] to [false]. No other occurrences of [Splitted] as a
constructor (rather than a pattern) exist in the code base.
*)assert(is_obj=false);(* we assert it's not an object *)assertfalse(* we assert false bc it's not an object *)|Delayedf->check_dup_fieldsvisitedfields(f())|Describe{encoding;_}->check_dup_fieldsvisitedfieldsencoding|Padded(_encoding,_)->assertfalse|Check_size{encoding=_;_}->assertfalse|String_enum_->assertfalse|Array_->assertfalse|List_->assertfalse|Tup_->assertfalse|Tups_->assertfalse|Null->assertfalse|Constant_->assertfalse|Bool->assertfalse|Int8->assertfalse|Uint8->assertfalse|Int16->assertfalse|Uint16->assertfalse|Int31->assertfalse|Int32->assertfalse|Int64->assertfalse|N->assertfalse|Z->assertfalse|RangedInt_->assertfalse|RangedFloat_->assertfalse|Float->assertfalse|Bytes_->assertfalse|String_->assertfalseletobj1f1=leto=obj1f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj2f2f1=leto=obj2f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj3f3f2f1=leto=obj3f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj4f4f3f2f1=leto=obj4f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj5f5f4f3f2f1=leto=obj5f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj6f6f5f4f3f2f1=leto=obj6f6f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj7f7f6f5f4f3f2f1=leto=obj7f7f6f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj8f8f7f6f5f4f3f2f1=leto=obj8f8f7f6f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj9f9f8f7f6f5f4f3f2f1=leto=obj9f9f8f7f6f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletobj10f10f9f8f7f6f5f4f3f2f1=leto=obj10f10f9f8f7f6f5f4f3f2f1inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoinoletmerge_objso1o2=leto=merge_objso1o2inlet_=check_dup_fieldsMu_visited.emptySSet.emptyoino(* Unions have an additional `kind` field *)letkind_field_name="kind"typecase_tag=Tagof(int*string)type'tcase='tEncoding.caseletcase~title?description(Tag(tag,kind))eprojinj=ifnot(is_obje)thenraise(Invalid_argument"Data_encoding.With_JSON_discriminant.case: encoding must be an obj");lete=merge_objs(obj1(reqkind_field_name(constantkind)))eincase~title?description(Encoding.Tagtag)e(funx->matchprojxwithNone->None|Somep->Some((),p))(fun((),x)->injx)letmatched?tag_size(tag,kind)ev=ifnot(is_obje)thenraise(Invalid_argument"Data_encoding.With_JSON_discriminant.case: encoding must be an obj");lete=merge_objs(obj1(reqkind_field_name(constantkind)))einmatched?tag_sizetag(conv(funx->((),x))(fun((),x)->x)e)vletcheck_case_listcases=List.fold_left(funkinds(Case{encoding=e;_})->matche.encodingwith|Objs{left={encoding=Obj(Req{name=kind_field_name_found;encoding={encoding=Constantkind;_};_;});_;};_;}whenkind_field_name_found=kind_field_name->(ifSSet.memkindkindsthenlets=Printf.sprintf"Data_encoding: two identical kind fields in union: %S"kindinraise(Invalid_arguments));SSet.addkindkinds|_->(* although the type [case] is an alias for [Encoding.case], the type
equality is hidden from the end-user in the library's interface
([data_encoding.mli]). As a result, it is not possible to construct
[Case]s with encodings other than
[merge_objs (obj1 (req "kind" (constant kind_field_name)))]. *)assertfalse)SSet.emptycasesletunion?tag_sizecases=let_=check_case_listcasesinunion?tag_sizecasesletmatching?tag_sizematch_casecases=let_=check_case_listcasesinmatching?tag_sizematch_casecases