@@ -336,87 +336,110 @@ func isOneOfCI(fl FieldLevel) bool {
336336func isUnique (fl FieldLevel ) bool {
337337 field := fl .Field ()
338338 param := fl .Param ()
339- v := reflect .ValueOf (struct {}{})
339+
340+ // sentinel used as map key for nil values
341+ var nilKey = struct {}{}
340342
341343 switch field .Kind () {
342344 case reflect .Slice , reflect .Array :
343- elem := field .Type ().Elem ()
344- if elem .Kind () == reflect .Ptr {
345- elem = elem .Elem ()
346- }
345+ seen := make (map [interface {}]struct {})
347346
348- if param == "" {
349- m := reflect .MakeMap (reflect .MapOf (elem , v .Type ()))
350- zero := reflect .Zero (elem )
347+ for i := 0 ; i < field .Len (); i ++ {
348+ elem := field .Index (i )
349+
350+ // -------- unique (no param) --------
351+ if param == "" {
352+ var key interface {}
353+
354+ if elem .Kind () == reflect .Ptr {
355+ if elem .IsNil () {
356+ key = nilKey
357+ } else {
358+ key = elem .Elem ().Interface () // <-- compare underlying value
359+ }
360+ } else {
361+ key = elem .Interface ()
362+ }
351363
352- for i := 0 ; i < field .Len (); i ++ {
353- e := reflect .Indirect (field .Index (i ))
354- if ! e .IsValid () {
355- m .SetMapIndex (zero , v )
356- continue
364+ if _ , ok := seen [key ]; ok {
365+ return false
357366 }
358- m .SetMapIndex (e , v )
367+ seen [key ] = struct {}{}
368+ continue
359369 }
360- return field .Len () == m .Len ()
361- }
362370
363- sf , ok := elem .FieldByName (param )
364- if ! ok {
365- panic (fmt .Sprintf ("Bad field name %s" , param ))
366- }
371+ // -------- unique=Field --------
367372
368- sfTyp := sf .Type
369- if sfTyp .Kind () == reflect .Ptr {
370- sfTyp = sfTyp .Elem ()
371- }
373+ if elem .Kind () == reflect .Ptr {
374+ if elem .IsNil () {
375+ if _ , ok := seen [nilKey ]; ok {
376+ return false
377+ }
378+ seen [nilKey ] = struct {}{}
379+ continue
380+ }
381+ elem = elem .Elem ()
382+ }
372383
373- m := reflect .MakeMap (reflect .MapOf (sfTyp , v .Type ()))
374- zero := reflect .Zero (sfTyp )
384+ if elem .Kind () != reflect .Struct {
385+ panic (fmt .Sprintf ("Bad field type %s" , elem .Type ()))
386+ }
375387
376- for i := 0 ; i < field .Len (); i ++ {
377- parent := reflect .Indirect (field .Index (i ))
378- if ! parent .IsValid () {
379- m .SetMapIndex (zero , v )
380- continue
388+ sf := elem .FieldByName (param )
389+ if ! sf .IsValid () {
390+ panic (fmt .Sprintf ("Bad field name %s" , param ))
381391 }
382392
383- key := reflect .Indirect (parent .FieldByName (param ))
384- if ! key .IsValid () {
385- m .SetMapIndex (zero , v )
386- continue
393+ var key interface {}
394+
395+ if sf .Kind () == reflect .Ptr {
396+ if sf .IsNil () {
397+ key = nilKey
398+ } else {
399+ key = sf .Elem ().Interface ()
400+ }
401+ } else {
402+ key = sf .Interface ()
387403 }
388404
389- m .SetMapIndex (key , v )
405+ if _ , ok := seen [key ]; ok {
406+ return false
407+ }
408+ seen [key ] = struct {}{}
390409 }
391410
392- return field . Len () == m . Len ()
411+ return true
393412
394413 case reflect .Map :
395- var keyType reflect.Type
396- if field .Type ().Elem ().Kind () == reflect .Ptr {
397- keyType = field .Type ().Elem ().Elem ()
398- } else {
399- keyType = field .Type ().Elem ()
400- }
401-
402- m := reflect .MakeMap (reflect .MapOf (keyType , v .Type ()))
403- zero := reflect .Zero (keyType )
414+ seen := make (map [interface {}]struct {})
404415
405416 for _ , k := range field .MapKeys () {
406- val := reflect .Indirect (field .MapIndex (k ))
407- if ! val .IsValid () {
408- m .SetMapIndex (zero , v )
409- continue
417+ val := field .MapIndex (k )
418+
419+ var key interface {}
420+
421+ if val .Kind () == reflect .Ptr {
422+ if val .IsNil () {
423+ key = nilKey
424+ } else {
425+ key = val .Elem ().Interface () // <-- compare underlying value
426+ }
427+ } else {
428+ key = val .Interface ()
429+ }
430+
431+ if _ , ok := seen [key ]; ok {
432+ return false
410433 }
411- m . SetMapIndex ( val , v )
434+ seen [ key ] = struct {}{}
412435 }
413436
414- return field . Len () == m . Len ()
437+ return true
415438
416439 default :
417440 if parent := fl .Parent (); parent .Kind () == reflect .Struct {
418441 uniqueField := parent .FieldByName (param )
419- if uniqueField == reflect . ValueOf ( nil ) {
442+ if ! uniqueField . IsValid ( ) {
420443 panic (fmt .Sprintf ("Bad field name provided %s" , param ))
421444 }
422445
0 commit comments