mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	use boxlayout from lazycore
This commit is contained in:
		
							
								
								
									
										7
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								go.mod
									
									
									
									
									
								
							| @@ -20,6 +20,7 @@ require ( | ||||
| 	github.com/jesseduffield/go-git/v5 v5.1.2-0.20201006095850-341962be15a4 | ||||
| 	github.com/jesseduffield/gocui v0.3.1-0.20221003162644-fead10f7b360 | ||||
| 	github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 | ||||
| 	github.com/jesseduffield/lazycore v0.0.0-20221009152330-3297d5700785 | ||||
| 	github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e | ||||
| 	github.com/jesseduffield/yaml v2.1.0+incompatible | ||||
| 	github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 | ||||
| @@ -29,15 +30,15 @@ require ( | ||||
| 	github.com/mgutz/str v1.2.0 | ||||
| 	github.com/pmezard/go-difflib v1.0.0 | ||||
| 	github.com/sahilm/fuzzy v0.1.0 | ||||
| 	github.com/samber/lo v1.10.1 | ||||
| 	github.com/samber/lo v1.31.0 | ||||
| 	github.com/sanity-io/litter v1.5.2 | ||||
| 	github.com/sasha-s/go-deadlock v0.3.1 | ||||
| 	github.com/sirupsen/logrus v1.4.2 | ||||
| 	github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad | ||||
| 	github.com/stretchr/testify v1.7.0 | ||||
| 	github.com/stretchr/testify v1.8.0 | ||||
| 	github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 | ||||
| 	gopkg.in/ozeidan/fuzzy-patricia.v3 v3.0.0 | ||||
| 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b | ||||
| 	gopkg.in/yaml.v3 v3.0.1 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
|   | ||||
							
								
								
									
										17
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								go.sum
									
									
									
									
									
								
							| @@ -76,6 +76,8 @@ github.com/jesseduffield/gocui v0.3.1-0.20221003162644-fead10f7b360 h1:43F6SAmNz | ||||
| github.com/jesseduffield/gocui v0.3.1-0.20221003162644-fead10f7b360/go.mod h1:znJuCDnF2Ph40YZSlBwdX/4GEofnIoWLGdT4mK5zRAU= | ||||
| github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 h1:jmpr7KpX2+2GRiE91zTgfq49QvgiqB0nbmlwZ8UnOx0= | ||||
| github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10/go.mod h1:aA97kHeNA+sj2Hbki0pvLslmE4CbDyhBeSSTUUnOuVo= | ||||
| github.com/jesseduffield/lazycore v0.0.0-20221009152330-3297d5700785 h1:o/XeosR2/jQgJPHjRuFABHFiXn51DsH35egR1h1ggo0= | ||||
| github.com/jesseduffield/lazycore v0.0.0-20221009152330-3297d5700785/go.mod h1:m8oQ2wqlXm/sFuDGuKTaX2BNsRJ+nW76J7vetOoMr0o= | ||||
| github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e h1:uw/oo+kg7t/oeMs6sqlAwr85ND/9cpO3up3VxphxY0U= | ||||
| github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e/go.mod h1:u60qdFGXRd36jyEXxetz0vQceQIxzI13lIo3EFUDf4I= | ||||
| github.com/jesseduffield/yaml v2.1.0+incompatible h1:HWQJ1gIv2zHKbDYNp0Jwjlj24K8aqpFHnMCynY1EpmE= | ||||
| @@ -139,8 +141,8 @@ github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= | ||||
| github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= | ||||
| github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= | ||||
| github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= | ||||
| github.com/samber/lo v1.10.1 h1:0D3h7i0U3hRAbaCeQ82DLe67n0A7Bbl0/cEoWqFGp+U= | ||||
| github.com/samber/lo v1.10.1/go.mod h1:2I7tgIv8Q1SG2xEIkRq0F2i2zgxVpnyPOP0d3Gj2r+A= | ||||
| github.com/samber/lo v1.31.0 h1:Sfa+/064Tdo4SvlohQUQzBhgSer9v/coGvKQI/XLWAM= | ||||
| github.com/samber/lo v1.31.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= | ||||
| github.com/sanity-io/litter v1.5.2 h1:AnC8s9BMORWH5a4atZ4D6FPVvKGzHcnc5/IVTa87myw= | ||||
| github.com/sanity-io/litter v1.5.2/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0= | ||||
| github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= | ||||
| @@ -152,14 +154,17 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd | ||||
| github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= | ||||
| github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= | ||||
| github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||||
| github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||
| github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||
| github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||||
| github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||
| github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= | ||||
| github.com/urfave/cli v1.20.1-0.20180226030253-8e01ec4cd3e2/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | ||||
| github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= | ||||
| @@ -223,5 +228,5 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package gui | ||||
|  | ||||
| import ( | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/boxlayout" | ||||
| 	"github.com/jesseduffield/lazycore/pkg/boxlayout" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/context" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/gui/types" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
|   | ||||
| @@ -1,380 +0,0 @@ | ||||
| package boxlayout | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestArrangeWindows(t *testing.T) { | ||||
| 	type scenario struct { | ||||
| 		testName string | ||||
| 		root     *Box | ||||
| 		x0       int | ||||
| 		y0       int | ||||
| 		width    int | ||||
| 		height   int | ||||
| 		test     func(result map[string]Dimensions) | ||||
| 	} | ||||
|  | ||||
| 	scenarios := []scenario{ | ||||
| 		{ | ||||
| 			testName: "Empty box", | ||||
| 			root:     &Box{}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues(t, result, map[string]Dimensions{}) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with static and dynamic panel", | ||||
| 			root:     &Box{Children: []*Box{{Size: 1, Window: "static"}, {Weight: 1, Window: "dynamic"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic": {X0: 0, X1: 9, Y0: 1, Y1: 9}, | ||||
| 						"static":  {X0: 0, X1: 9, Y0: 0, Y1: 0}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with static and two dynamic panels", | ||||
| 			root:     &Box{Children: []*Box{{Size: 1, Window: "static"}, {Weight: 1, Window: "dynamic1"}, {Weight: 2, Window: "dynamic2"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"static":   {X0: 0, X1: 9, Y0: 0, Y1: 0}, | ||||
| 						"dynamic1": {X0: 0, X1: 9, Y0: 1, Y1: 3}, | ||||
| 						"dynamic2": {X0: 0, X1: 9, Y0: 4, Y1: 9}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with COLUMN direction", | ||||
| 			root:     &Box{Direction: COLUMN, Children: []*Box{{Size: 1, Window: "static"}, {Weight: 1, Window: "dynamic1"}, {Weight: 2, Window: "dynamic2"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"static":   {X0: 0, X1: 0, Y0: 0, Y1: 9}, | ||||
| 						"dynamic1": {X0: 1, X1: 3, Y0: 0, Y1: 9}, | ||||
| 						"dynamic2": {X0: 4, X1: 9, Y0: 0, Y1: 9}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with COLUMN direction only on wide boxes with narrow box", | ||||
| 			root: &Box{ConditionalDirection: func(width int, height int) Direction { | ||||
| 				if width > 4 { | ||||
| 					return COLUMN | ||||
| 				} else { | ||||
| 					return ROW | ||||
| 				} | ||||
| 			}, Children: []*Box{{Weight: 1, Window: "dynamic1"}, {Weight: 1, Window: "dynamic2"}}}, | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  4, | ||||
| 			height: 4, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 3, Y0: 0, Y1: 1}, | ||||
| 						"dynamic2": {X0: 0, X1: 3, Y0: 2, Y1: 3}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with COLUMN direction only on wide boxes with wide box", | ||||
| 			root: &Box{ConditionalDirection: func(width int, height int) Direction { | ||||
| 				if width > 4 { | ||||
| 					return COLUMN | ||||
| 				} else { | ||||
| 					return ROW | ||||
| 				} | ||||
| 			}, Children: []*Box{{Weight: 1, Window: "dynamic1"}, {Weight: 1, Window: "dynamic2"}}}, | ||||
| 			// 5 / 2 = 2 remainder 1. That remainder goes to the first box. | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  5, | ||||
| 			height: 5, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 2, Y0: 0, Y1: 4}, | ||||
| 						"dynamic2": {X0: 3, X1: 4, Y0: 0, Y1: 4}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with conditional children where box is wide", | ||||
| 			root: &Box{ConditionalChildren: func(width int, height int) []*Box { | ||||
| 				if width > 4 { | ||||
| 					return []*Box{{Window: "wide", Weight: 1}} | ||||
| 				} else { | ||||
| 					return []*Box{{Window: "narrow", Weight: 1}} | ||||
| 				} | ||||
| 			}}, | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  5, | ||||
| 			height: 5, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"wide": {X0: 0, X1: 4, Y0: 0, Y1: 4}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with conditional children where box is narrow", | ||||
| 			root: &Box{ConditionalChildren: func(width int, height int) []*Box { | ||||
| 				if width > 4 { | ||||
| 					return []*Box{{Window: "wide", Weight: 1}} | ||||
| 				} else { | ||||
| 					return []*Box{{Window: "narrow", Weight: 1}} | ||||
| 				} | ||||
| 			}}, | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  4, | ||||
| 			height: 4, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"narrow": {X0: 0, X1: 3, Y0: 0, Y1: 3}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with static child with size too large", | ||||
| 			root:     &Box{Direction: COLUMN, Children: []*Box{{Size: 11, Window: "static"}, {Weight: 1, Window: "dynamic1"}, {Weight: 2, Window: "dynamic2"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"static": {X0: 0, X1: 9, Y0: 0, Y1: 9}, | ||||
| 						// not sure if X0: 10, X1: 9 makes any sense, but testing this in the | ||||
| 						// actual GUI it seems harmless | ||||
| 						"dynamic1": {X0: 10, X1: 9, Y0: 0, Y1: 9}, | ||||
| 						"dynamic2": {X0: 10, X1: 9, Y0: 0, Y1: 9}, | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// 10 total space minus 2 from the status box leaves us with 8. | ||||
| 			// Total weight is 3, 8 / 3 = 2 with 2 remainder. | ||||
| 			// We want to end up with 2, 3, 5 (one unit from remainder to each dynamic box) | ||||
| 			testName: "Distributing remainder across weighted boxes", | ||||
| 			root:     &Box{Direction: COLUMN, Children: []*Box{{Size: 2, Window: "static"}, {Weight: 1, Window: "dynamic1"}, {Weight: 2, Window: "dynamic2"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    10, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"static":   {X0: 0, X1: 1, Y0: 0, Y1: 9}, // 2 | ||||
| 						"dynamic1": {X0: 2, X1: 4, Y0: 0, Y1: 9}, // 3 | ||||
| 						"dynamic2": {X0: 5, X1: 9, Y0: 0, Y1: 9}, // 5 | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// 9 total space. | ||||
| 			// total weight is 5, 9 / 5 = 1 with 4 remainder | ||||
| 			// we want to give 2 of that remainder to the first, 1 to the second, and 1 to the last. | ||||
| 			// Reason being that we just give units to each box evenly and consider weight in subsequent passes. | ||||
| 			testName: "Distributing remainder across weighted boxes 2", | ||||
| 			root:     &Box{Direction: COLUMN, Children: []*Box{{Weight: 2, Window: "dynamic1"}, {Weight: 2, Window: "dynamic2"}, {Weight: 1, Window: "dynamic3"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    9, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 3, Y0: 0, Y1: 9}, // 4 | ||||
| 						"dynamic2": {X0: 4, X1: 6, Y0: 0, Y1: 9}, // 3 | ||||
| 						"dynamic3": {X0: 7, X1: 8, Y0: 0, Y1: 9}, // 2 | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// 9 total space. | ||||
| 			// total weight is 5, 9 / 5 = 1 with 4 remainder | ||||
| 			// we want to give 2 of that remainder to the first, 1 to the second, and 1 to the last. | ||||
| 			// Reason being that we just give units to each box evenly and consider weight in subsequent passes. | ||||
| 			testName: "Distributing remainder across weighted boxes with unnormalized weights", | ||||
| 			root:     &Box{Direction: COLUMN, Children: []*Box{{Weight: 4, Window: "dynamic1"}, {Weight: 4, Window: "dynamic2"}, {Weight: 2, Window: "dynamic3"}}}, | ||||
| 			x0:       0, | ||||
| 			y0:       0, | ||||
| 			width:    9, | ||||
| 			height:   10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 3, Y0: 0, Y1: 9}, // 4 | ||||
| 						"dynamic2": {X0: 4, X1: 6, Y0: 0, Y1: 9}, // 3 | ||||
| 						"dynamic3": {X0: 7, X1: 8, Y0: 0, Y1: 9}, // 2 | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Another distribution test", | ||||
| 			root: &Box{Direction: COLUMN, Children: []*Box{ | ||||
| 				{Weight: 3, Window: "dynamic1"}, | ||||
| 				{Weight: 1, Window: "dynamic2"}, | ||||
| 				{Weight: 1, Window: "dynamic3"}, | ||||
| 			}}, | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  9, | ||||
| 			height: 10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 4, Y0: 0, Y1: 9}, // 5 | ||||
| 						"dynamic2": {X0: 5, X1: 6, Y0: 0, Y1: 9}, // 2 | ||||
| 						"dynamic3": {X0: 7, X1: 8, Y0: 0, Y1: 9}, // 2 | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "Box with zero weight", | ||||
| 			root: &Box{Direction: COLUMN, Children: []*Box{ | ||||
| 				{Weight: 1, Window: "dynamic1"}, | ||||
| 				{Weight: 0, Window: "dynamic2"}, | ||||
| 			}}, | ||||
| 			x0:     0, | ||||
| 			y0:     0, | ||||
| 			width:  10, | ||||
| 			height: 10, | ||||
| 			test: func(result map[string]Dimensions) { | ||||
| 				assert.EqualValues( | ||||
| 					t, | ||||
| 					result, | ||||
| 					map[string]Dimensions{ | ||||
| 						"dynamic1": {X0: 0, X1: 9, Y0: 0, Y1: 9}, | ||||
| 						"dynamic2": {X0: 10, X1: 9, Y0: 0, Y1: 9}, // when X0 > X1, we will hide the window | ||||
| 					}, | ||||
| 				) | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range scenarios { | ||||
| 		s := s | ||||
| 		t.Run(s.testName, func(t *testing.T) { | ||||
| 			s.test(ArrangeWindows(s.root, s.x0, s.y0, s.width, s.height)) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestNormalizeWeights(t *testing.T) { | ||||
| 	scenarios := []struct { | ||||
| 		testName string | ||||
| 		input    []int | ||||
| 		expected []int | ||||
| 	}{ | ||||
| 		{ | ||||
| 			testName: "empty", | ||||
| 			input:    []int{}, | ||||
| 			expected: []int{}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "one item of value 1", | ||||
| 			input:    []int{1}, | ||||
| 			expected: []int{1}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "one item of value greater than 1", | ||||
| 			input:    []int{2}, | ||||
| 			expected: []int{1}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "slice contains 1", | ||||
| 			input:    []int{2, 1}, | ||||
| 			expected: []int{2, 1}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "slice contains 2 and 2", | ||||
| 			input:    []int{2, 2}, | ||||
| 			expected: []int{1, 1}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "no common multiple", | ||||
| 			input:    []int{2, 3}, | ||||
| 			expected: []int{2, 3}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "complex case", | ||||
| 			input:    []int{10, 10, 20}, | ||||
| 			expected: []int{1, 1, 2}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			testName: "when a zero weight is included it is ignored", | ||||
| 			input:    []int{10, 10, 20, 0}, | ||||
| 			expected: []int{1, 1, 2, 0}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range scenarios { | ||||
| 		s := s | ||||
| 		t.Run(s.testName, func(t *testing.T) { | ||||
| 			assert.EqualValues(t, s.expected, normalizeWeights(s.input)) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/github.com/jesseduffield/lazycore/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/jesseduffield/lazycore/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| MIT License | ||||
|  | ||||
| Copyright (c) 2022 Jesse Duffield | ||||
|  | ||||
| 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. | ||||
| @@ -2,7 +2,7 @@ package boxlayout | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/jesseduffield/generics/slices" | ||||
| 	"github.com/jesseduffield/lazygit/pkg/utils" | ||||
| 	"github.com/jesseduffield/lazycore/pkg/utils" | ||||
| 	"github.com/samber/lo" | ||||
| ) | ||||
| 
 | ||||
							
								
								
									
										16
									
								
								vendor/github.com/jesseduffield/lazycore/pkg/utils/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/jesseduffield/lazycore/pkg/utils/utils.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| package utils | ||||
|  | ||||
| // Min returns the minimum of two integers | ||||
| func Min(x, y int) int { | ||||
| 	if x < y { | ||||
| 		return x | ||||
| 	} | ||||
| 	return y | ||||
| } | ||||
|  | ||||
| func Max(x, y int) int { | ||||
| 	if x > y { | ||||
| 		return x | ||||
| 	} | ||||
| 	return y | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/samber/lo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/samber/lo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -34,3 +34,5 @@ go.work | ||||
| cover.out | ||||
| cover.html | ||||
| .vscode | ||||
|  | ||||
| .idea/ | ||||
|   | ||||
							
								
								
									
										276
									
								
								vendor/github.com/samber/lo/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										276
									
								
								vendor/github.com/samber/lo/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,281 @@ | ||||
| # Changelog | ||||
|  | ||||
| @samber: I sometimes forget to update this file. Ping me on [Twitter](https://twitter.com/samuelberthe) or open an issue in case of error. We need to keep a clear changelog for easier lib upgrade. | ||||
|  | ||||
| ## 1.31.0 (2022-10-06) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.SliceToChannel | ||||
| - lo.Generator | ||||
| - lo.Batch | ||||
| - lo.BatchWithTimeout | ||||
|  | ||||
| ## 1.30.1 (2022-10-06) | ||||
|  | ||||
| Fix: | ||||
|  | ||||
| - lo.Try1: remove generic type | ||||
| - lo.Validate: format error properly | ||||
|  | ||||
| ## 1.30.0 (2022-10-04) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.TernaryF | ||||
| - lo.Validate | ||||
|  | ||||
| ## 1.29.0 (2022-10-02) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.ErrorAs | ||||
| - lo.TryOr | ||||
| - lo.TryOrX | ||||
|  | ||||
| ## 1.28.0 (2022-09-05) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.ChannelDispatcher with 6 dispatching strategies: | ||||
|   - lo.DispatchingStrategyRoundRobin | ||||
|   - lo.DispatchingStrategyRandom | ||||
|   - lo.DispatchingStrategyWeightedRandom | ||||
|   - lo.DispatchingStrategyFirst | ||||
|   - lo.DispatchingStrategyLeast | ||||
|   - lo.DispatchingStrategyMost | ||||
|  | ||||
| ## 1.27.1 (2022-08-15) | ||||
|  | ||||
| Bugfix: | ||||
|  | ||||
| - Removed comparable constraint for lo.FindKeyBy | ||||
|  | ||||
| ## 1.27.0 (2022-07-29) | ||||
|  | ||||
| Breaking: | ||||
|  | ||||
| - Change of MapToSlice prototype: `MapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(V, K) R) []R` -> `MapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(K, V) R) []R` | ||||
|  | ||||
| Added: | ||||
|  | ||||
| - lo.ChunkString | ||||
| - lo.SliceToMap (alias to lo.Associate) | ||||
|  | ||||
| ## 1.26.0 (2022-07-24) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Associate | ||||
| - lo.ReduceRight | ||||
| - lo.FromPtrOr | ||||
| - lo.MapToSlice | ||||
| - lo.IsSorted | ||||
| - lo.IsSortedByKey | ||||
|  | ||||
| ## 1.25.0 (2022-07-04) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.FindUniques | ||||
| - lo.FindUniquesBy | ||||
| - lo.FindDuplicates | ||||
| - lo.FindDuplicatesBy | ||||
| - lo.IsNotEmpty | ||||
|  | ||||
| ## 1.24.0 (2022-07-04) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Without | ||||
| - lo.WithoutEmpty | ||||
|  | ||||
| ## 1.23.0 (2022-07-04) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.FindKey | ||||
| - lo.FindKeyBy | ||||
|  | ||||
| ## 1.22.0 (2022-07-04) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Slice | ||||
| - lo.FromPtr | ||||
| - lo.IsEmpty | ||||
| - lo.Compact | ||||
| - lo.ToPairs: alias to lo.Entries | ||||
| - lo.FromPairs: alias to lo.FromEntries | ||||
| - lo.Partial | ||||
|  | ||||
| Change: | ||||
|  | ||||
| - lo.Must + lo.MustX: add context to panic message | ||||
|  | ||||
| Fix: | ||||
|  | ||||
| - lo.Nth: out of bound exception (#137) | ||||
|  | ||||
| ## 1.21.0 (2022-05-10) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.ToAnySlice | ||||
| - lo.FromAnySlice | ||||
|  | ||||
| ## 1.20.0 (2022-05-02) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Synchronize | ||||
| - lo.SumBy | ||||
|  | ||||
| Change: | ||||
| - Removed generic type definition for lo.Try0: `lo.Try0[T]()` -> `lo.Try0()` | ||||
|  | ||||
| ## 1.19.0 (2022-04-30) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.RepeatBy | ||||
| - lo.Subset | ||||
| - lo.Replace | ||||
| - lo.ReplaceAll | ||||
| - lo.Substring | ||||
| - lo.RuneLength | ||||
|  | ||||
| ## 1.18.0 (2022-04-28) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.SomeBy | ||||
| - lo.EveryBy | ||||
| - lo.None | ||||
| - lo.NoneBy | ||||
|  | ||||
| ## 1.17.0 (2022-04-27) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Unpack2 -> lo.Unpack3 | ||||
| - lo.Async0 -> lo.Async6 | ||||
|  | ||||
| ## 1.16.0 (2022-04-26) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.AttemptWithDelay | ||||
|  | ||||
| ## 1.15.0 (2022-04-22) | ||||
|  | ||||
| Improvement: | ||||
|  | ||||
| - lo.Must: error or boolean value | ||||
|  | ||||
| ## 1.14.0 (2022-04-21) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - lo.Coalesce | ||||
|  | ||||
| ## 1.13.0 (2022-04-14) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - PickBy | ||||
| - PickByKeys | ||||
| - PickByValues | ||||
| - OmitBy | ||||
| - OmitByKeys | ||||
| - OmitByValues | ||||
| - Clamp | ||||
| - MapKeys | ||||
| - Invert | ||||
| - IfF + ElseIfF + ElseF | ||||
| - T0() + T1() + T2() + T3() + ... | ||||
|  | ||||
| ## 1.12.0 (2022-04-12) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - Must | ||||
| - Must{0-6} | ||||
| - FindOrElse | ||||
| - Async | ||||
| - MinBy | ||||
| - MaxBy | ||||
| - Count | ||||
| - CountBy | ||||
| - FindIndexOf | ||||
| - FindLastIndexOf | ||||
| - FilterMap | ||||
|  | ||||
| ## 1.11.0 (2022-03-11) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - Try | ||||
| - Try{0-6} | ||||
| - TryWitchValue | ||||
| - TryCatch | ||||
| - TryCatchWitchValue | ||||
| - Debounce | ||||
| - Reject | ||||
|  | ||||
| ## 1.10.0 (2022-03-11) | ||||
|  | ||||
| Adding: | ||||
|  | ||||
| - Range | ||||
| - RangeFrom | ||||
| - RangeWithSteps | ||||
|  | ||||
| ## 1.9.0 (2022-03-10) | ||||
|  | ||||
| Added | ||||
|  | ||||
| - Drop | ||||
| - DropRight | ||||
| - DropWhile | ||||
| - DropRightWhile | ||||
|  | ||||
| ## 1.8.0 (2022-03-10) | ||||
|  | ||||
| Adding Union. | ||||
|  | ||||
| ## 1.7.0 (2022-03-09) | ||||
|  | ||||
| Adding ContainBy | ||||
|  | ||||
| Adding MapValues | ||||
|  | ||||
| Adding FlatMap | ||||
|  | ||||
| ## 1.6.0 (2022-03-07) | ||||
|  | ||||
| Fixed PartitionBy. | ||||
|  | ||||
| Adding Sample | ||||
|  | ||||
| Adding Samples | ||||
|  | ||||
| ## 1.5.0 (2022-03-07) | ||||
|  | ||||
| Adding Times | ||||
|  | ||||
| Adding Attempt | ||||
|  | ||||
| Adding Repeat | ||||
|  | ||||
| ## 1.4.0 (2022-03-07) | ||||
|  | ||||
| - adding tuple types (2->9) | ||||
| - adding Zip + Unzip | ||||
| - adding lo.PartitionBy + lop.PartitionBy | ||||
| - adding lop.GroupBy | ||||
| - fixing Nth | ||||
|  | ||||
| ## 1.3.0 (2022-03-03) | ||||
|  | ||||
| Last and Nth return errors | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/samber/lo/Dockerfile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/samber/lo/Dockerfile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +1,8 @@ | ||||
|  | ||||
| FROM golang:1.18rc1-bullseye | ||||
| FROM golang:1.18 | ||||
|  | ||||
| WORKDIR /go/src/github.com/samber/lo | ||||
|  | ||||
| COPY Makefile go.* /go/src/github.com/samber/lo/ | ||||
| COPY Makefile go.* ./ | ||||
|  | ||||
| RUN make tools | ||||
|   | ||||
							
								
								
									
										15
									
								
								vendor/github.com/samber/lo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/samber/lo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,10 +1,5 @@ | ||||
|  | ||||
| BIN=go | ||||
| # BIN=go1.18beta1 | ||||
|  | ||||
| go1.18beta1: | ||||
| 	go install golang.org/dl/go1.18beta1@latest | ||||
| 	go1.18beta1 download | ||||
|  | ||||
| build: | ||||
| 	${BIN} build -v ./... | ||||
| @@ -12,15 +7,15 @@ build: | ||||
| test: | ||||
| 	go test -race -v ./... | ||||
| watch-test: | ||||
| 	reflex -R assets.go -t 50ms -s -- sh -c 'gotest -race -v ./...' | ||||
| 	reflex -t 50ms -s -- sh -c 'gotest -race -v ./...' | ||||
|  | ||||
| bench: | ||||
| 	go test -benchmem -count 3 -bench ./... | ||||
| watch-bench: | ||||
| 	reflex -R assets.go -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...' | ||||
| 	reflex -t 50ms -s -- sh -c 'go test -benchmem -count 3 -bench ./...' | ||||
|  | ||||
| coverage: | ||||
| 	${BIN} test -v -coverprofile cover.out . | ||||
| 	${BIN} test -v -coverprofile=cover.out -covermode=atomic . | ||||
| 	${BIN} tool cover -html=cover.out -o cover.html | ||||
|  | ||||
| # tools | ||||
| @@ -31,7 +26,7 @@ tools: | ||||
| 	${BIN} install github.com/jondot/goweight@latest | ||||
| 	${BIN} install github.com/golangci/golangci-lint/cmd/golangci-lint@latest | ||||
| 	${BIN} get -t -u golang.org/x/tools/cmd/cover | ||||
| 	${BIN} get -t -u github.com/sonatype-nexus-community/nancy@latest | ||||
| 	${BIN} install github.com/sonatype-nexus-community/nancy@latest | ||||
| 	go mod tidy | ||||
|  | ||||
| lint: | ||||
| @@ -40,11 +35,9 @@ lint-fix: | ||||
| 	golangci-lint run --timeout 60s --max-same-issues 50 --fix ./... | ||||
|  | ||||
| audit: tools | ||||
| 	${BIN} mod tidy | ||||
| 	${BIN} list -json -m all | nancy sleuth | ||||
|  | ||||
| outdated: tools | ||||
| 	${BIN} mod tidy | ||||
| 	${BIN} list -u -m -json all | go-mod-outdated -update -direct | ||||
|  | ||||
| weight: tools | ||||
|   | ||||
							
								
								
									
										1833
									
								
								vendor/github.com/samber/lo/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1833
									
								
								vendor/github.com/samber/lo/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										228
									
								
								vendor/github.com/samber/lo/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								vendor/github.com/samber/lo/channel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,228 @@ | ||||
| package lo | ||||
|  | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type DispatchingStrategy[T any] func(msg T, index uint64, channels []<-chan T) int | ||||
|  | ||||
| // ChannelDispatcher distributes messages from input channels into N child channels. | ||||
| // Close events are propagated to children. | ||||
| // Underlying channels can have a fixed buffer capacity or be unbuffered when cap is 0. | ||||
| func ChannelDispatcher[T any](stream <-chan T, count int, channelBufferCap int, strategy DispatchingStrategy[T]) []<-chan T { | ||||
| 	children := createChannels[T](count, channelBufferCap) | ||||
|  | ||||
| 	roChildren := channelsToReadOnly(children) | ||||
|  | ||||
| 	go func() { | ||||
| 		// propagate channel closing to children | ||||
| 		defer closeChannels(children) | ||||
|  | ||||
| 		var i uint64 = 0 | ||||
|  | ||||
| 		for { | ||||
| 			msg, ok := <-stream | ||||
| 			if !ok { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			destination := strategy(msg, i, roChildren) % count | ||||
| 			children[destination] <- msg | ||||
|  | ||||
| 			i++ | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	return roChildren | ||||
| } | ||||
|  | ||||
| func createChannels[T any](count int, channelBufferCap int) []chan T { | ||||
| 	children := make([]chan T, 0, count) | ||||
|  | ||||
| 	for i := 0; i < count; i++ { | ||||
| 		children = append(children, make(chan T, channelBufferCap)) | ||||
| 	} | ||||
|  | ||||
| 	return children | ||||
| } | ||||
|  | ||||
| func channelsToReadOnly[T any](children []chan T) []<-chan T { | ||||
| 	roChildren := make([]<-chan T, 0, len(children)) | ||||
|  | ||||
| 	for i := range children { | ||||
| 		roChildren = append(roChildren, children[i]) | ||||
| 	} | ||||
|  | ||||
| 	return roChildren | ||||
| } | ||||
|  | ||||
| func closeChannels[T any](children []chan T) { | ||||
| 	for i := 0; i < len(children); i++ { | ||||
| 		close(children[i]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func channelIsNotFull[T any](ch <-chan T) bool { | ||||
| 	return cap(ch) == 0 || len(ch) < cap(ch) | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyRoundRobin distributes messages in a rotating sequential manner. | ||||
| // If the channel capacity is exceeded, the next channel will be selected and so on. | ||||
| func DispatchingStrategyRoundRobin[T any](msg T, index uint64, channels []<-chan T) int { | ||||
| 	for { | ||||
| 		i := int(index % uint64(len(channels))) | ||||
| 		if channelIsNotFull(channels[i]) { | ||||
| 			return i | ||||
| 		} | ||||
|  | ||||
| 		index++ | ||||
| 		time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyRandom distributes messages in a random manner. | ||||
| // If the channel capacity is exceeded, another random channel will be selected and so on. | ||||
| func DispatchingStrategyRandom[T any](msg T, index uint64, channels []<-chan T) int { | ||||
| 	for { | ||||
| 		i := rand.Intn(len(channels)) | ||||
| 		if channelIsNotFull(channels[i]) { | ||||
| 			return i | ||||
| 		} | ||||
|  | ||||
| 		time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyRandom distributes messages in a weighted manner. | ||||
| // If the channel capacity is exceeded, another random channel will be selected and so on. | ||||
| func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy[T] { | ||||
| 	seq := []int{} | ||||
|  | ||||
| 	for i := 0; i < len(weights); i++ { | ||||
| 		for j := 0; j < weights[i]; j++ { | ||||
| 			seq = append(seq, i) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return func(msg T, index uint64, channels []<-chan T) int { | ||||
| 		for { | ||||
| 			i := seq[rand.Intn(len(seq))] | ||||
| 			if channelIsNotFull(channels[i]) { | ||||
| 				return i | ||||
| 			} | ||||
|  | ||||
| 			time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyFirst distributes messages in the first non-full channel. | ||||
| // If the capacity of the first channel is exceeded, the second channel will be selected and so on. | ||||
| func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) int { | ||||
| 	for { | ||||
| 		for i := range channels { | ||||
| 			if channelIsNotFull(channels[i]) { | ||||
| 				return i | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		time.Sleep(10 * time.Microsecond) // prevent CPU from burning 🔥 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyLeast distributes messages in the emptiest channel. | ||||
| func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) int { | ||||
| 	seq := Range(len(channels)) | ||||
|  | ||||
| 	return MinBy(seq, func(item int, min int) bool { | ||||
| 		return len(channels[item]) < len(channels[min]) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // DispatchingStrategyMost distributes messages in the fulliest channel. | ||||
| // If the channel capacity is exceeded, the next channel will be selected and so on. | ||||
| func DispatchingStrategyMost[T any](msg T, index uint64, channels []<-chan T) int { | ||||
| 	seq := Range(len(channels)) | ||||
|  | ||||
| 	return MaxBy(seq, func(item int, max int) bool { | ||||
| 		return len(channels[item]) > len(channels[max]) && channelIsNotFull(channels[item]) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // SliceToChannel returns a read-only channels of collection elements. | ||||
| func SliceToChannel[T any](bufferSize int, collection []T) <-chan T { | ||||
| 	ch := make(chan T, bufferSize) | ||||
|  | ||||
| 	go func() { | ||||
| 		for _, item := range collection { | ||||
| 			ch <- item | ||||
| 		} | ||||
|  | ||||
| 		close(ch) | ||||
| 	}() | ||||
|  | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Generator implements the generator design pattern. | ||||
| func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T { | ||||
| 	ch := make(chan T, bufferSize) | ||||
|  | ||||
| 	go func() { | ||||
| 		// WARNING: infinite loop | ||||
| 		generator(func(t T) { | ||||
| 			ch <- t | ||||
| 		}) | ||||
|  | ||||
| 		close(ch) | ||||
| 	}() | ||||
|  | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Batch creates a slice of n elements from a channel. Returns the slice and the slice length. | ||||
| // @TODO: we should probaby provide an helper that reuse the same buffer. | ||||
| func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) { | ||||
| 	buffer := make([]T, 0, size) | ||||
| 	index := 0 | ||||
| 	now := time.Now() | ||||
|  | ||||
| 	for ; index < size; index++ { | ||||
| 		item, ok := <-ch | ||||
| 		if !ok { | ||||
| 			return buffer, index, time.Since(now), false | ||||
| 		} | ||||
|  | ||||
| 		buffer = append(buffer, item) | ||||
| 	} | ||||
|  | ||||
| 	return buffer, index, time.Since(now), true | ||||
| } | ||||
|  | ||||
| // BatchWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length. | ||||
| // @TODO: we should probaby provide an helper that reuse the same buffer. | ||||
| func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) { | ||||
| 	expire := time.NewTimer(timeout) | ||||
| 	defer expire.Stop() | ||||
|  | ||||
| 	buffer := make([]T, 0, size) | ||||
| 	index := 0 | ||||
| 	now := time.Now() | ||||
|  | ||||
| 	for ; index < size; index++ { | ||||
| 		select { | ||||
| 		case item, ok := <-ch: | ||||
| 			if !ok { | ||||
| 				return buffer, index, time.Since(now), false | ||||
| 			} | ||||
|  | ||||
| 			buffer = append(buffer, item) | ||||
|  | ||||
| 		case <-expire.C: | ||||
| 			return buffer, index, time.Since(now), true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return buffer, index, time.Since(now), true | ||||
| } | ||||
							
								
								
									
										95
									
								
								vendor/github.com/samber/lo/concurrency.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/samber/lo/concurrency.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| package lo | ||||
|  | ||||
| import "sync" | ||||
|  | ||||
| type synchronize struct { | ||||
| 	locker sync.Locker | ||||
| } | ||||
|  | ||||
| func (s *synchronize) Do(cb func()) { | ||||
| 	s.locker.Lock() | ||||
| 	Try0(cb) | ||||
| 	s.locker.Unlock() | ||||
| } | ||||
|  | ||||
| // Synchronize wraps the underlying callback in a mutex. It receives an optional mutex. | ||||
| func Synchronize(opt ...sync.Locker) *synchronize { | ||||
| 	if len(opt) > 1 { | ||||
| 		panic("unexpected arguments") | ||||
| 	} else if len(opt) == 0 { | ||||
| 		opt = append(opt, &sync.Mutex{}) | ||||
| 	} | ||||
|  | ||||
| 	return &synchronize{ | ||||
| 		locker: opt[0], | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Async executes a function in a goroutine and returns the result in a channel. | ||||
| func Async[A any](f func() A) chan A { | ||||
| 	ch := make(chan A) | ||||
| 	go func() { | ||||
| 		ch <- f() | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async0 executes a function in a goroutine and returns a channel set once the function finishes. | ||||
| func Async0(f func()) chan struct{} { | ||||
| 	ch := make(chan struct{}) | ||||
| 	go func() { | ||||
| 		f() | ||||
| 		ch <- struct{}{} | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async1 is an alias to Async. | ||||
| func Async1[A any](f func() A) chan A { | ||||
| 	return Async(f) | ||||
| } | ||||
|  | ||||
| // Async2 has the same behavior as Async, but returns the 2 results as a tuple inside the channel. | ||||
| func Async2[A any, B any](f func() (A, B)) chan Tuple2[A, B] { | ||||
| 	ch := make(chan Tuple2[A, B]) | ||||
| 	go func() { | ||||
| 		ch <- T2(f()) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async3 has the same behavior as Async, but returns the 3 results as a tuple inside the channel. | ||||
| func Async3[A any, B any, C any](f func() (A, B, C)) chan Tuple3[A, B, C] { | ||||
| 	ch := make(chan Tuple3[A, B, C]) | ||||
| 	go func() { | ||||
| 		ch <- T3(f()) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async4 has the same behavior as Async, but returns the 4 results as a tuple inside the channel. | ||||
| func Async4[A any, B any, C any, D any](f func() (A, B, C, D)) chan Tuple4[A, B, C, D] { | ||||
| 	ch := make(chan Tuple4[A, B, C, D]) | ||||
| 	go func() { | ||||
| 		ch <- T4(f()) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async5 has the same behavior as Async, but returns the 5 results as a tuple inside the channel. | ||||
| func Async5[A any, B any, C any, D any, E any](f func() (A, B, C, D, E)) chan Tuple5[A, B, C, D, E] { | ||||
| 	ch := make(chan Tuple5[A, B, C, D, E]) | ||||
| 	go func() { | ||||
| 		ch <- T5(f()) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // Async6 has the same behavior as Async, but returns the 6 results as a tuple inside the channel. | ||||
| func Async6[A any, B any, C any, D any, E any, F any](f func() (A, B, C, D, E, F)) chan Tuple6[A, B, C, D, E, F] { | ||||
| 	ch := make(chan Tuple6[A, B, C, D, E, F]) | ||||
| 	go func() { | ||||
| 		ch <- T6(f()) | ||||
| 	}() | ||||
| 	return ch | ||||
| } | ||||
							
								
								
									
										51
									
								
								vendor/github.com/samber/lo/condition.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/samber/lo/condition.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| package lo | ||||
|  | ||||
| // Ternary is a 1 line if/else statement. | ||||
| // Play: https://go.dev/play/p/t-D7WBL44h2 | ||||
| func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { | ||||
| 	if condition { | ||||
| 		return ifOutput | ||||
| @@ -9,12 +10,23 @@ func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { | ||||
| 	return elseOutput | ||||
| } | ||||
|  | ||||
| // TernaryF is a 1 line if/else statement whose options are functions | ||||
| // Play: https://go.dev/play/p/AO4VW20JoqM | ||||
| func TernaryF[T any](condition bool, ifFunc func() T, elseFunc func() T) T { | ||||
| 	if condition { | ||||
| 		return ifFunc() | ||||
| 	} | ||||
|  | ||||
| 	return elseFunc() | ||||
| } | ||||
|  | ||||
| type ifElse[T any] struct { | ||||
| 	result T | ||||
| 	done   bool | ||||
| } | ||||
|  | ||||
| // If. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func If[T any](condition bool, result T) *ifElse[T] { | ||||
| 	if condition { | ||||
| 		return &ifElse[T]{result, true} | ||||
| @@ -24,7 +36,19 @@ func If[T any](condition bool, result T) *ifElse[T] { | ||||
| 	return &ifElse[T]{t, false} | ||||
| } | ||||
|  | ||||
| // IfF. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func IfF[T any](condition bool, resultF func() T) *ifElse[T] { | ||||
| 	if condition { | ||||
| 		return &ifElse[T]{resultF(), true} | ||||
| 	} | ||||
|  | ||||
| 	var t T | ||||
| 	return &ifElse[T]{t, false} | ||||
| } | ||||
|  | ||||
| // ElseIf. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func (i *ifElse[T]) ElseIf(condition bool, result T) *ifElse[T] { | ||||
| 	if !i.done && condition { | ||||
| 		i.result = result | ||||
| @@ -34,7 +58,19 @@ func (i *ifElse[T]) ElseIf(condition bool, result T) *ifElse[T] { | ||||
| 	return i | ||||
| } | ||||
|  | ||||
| // ElseIfF. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func (i *ifElse[T]) ElseIfF(condition bool, resultF func() T) *ifElse[T] { | ||||
| 	if !i.done && condition { | ||||
| 		i.result = resultF() | ||||
| 		i.done = true | ||||
| 	} | ||||
|  | ||||
| 	return i | ||||
| } | ||||
|  | ||||
| // Else. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func (i *ifElse[T]) Else(result T) T { | ||||
| 	if i.done { | ||||
| 		return i.result | ||||
| @@ -43,6 +79,16 @@ func (i *ifElse[T]) Else(result T) T { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // ElseF. | ||||
| // Play: https://go.dev/play/p/WSw3ApMxhyW | ||||
| func (i *ifElse[T]) ElseF(resultF func() T) T { | ||||
| 	if i.done { | ||||
| 		return i.result | ||||
| 	} | ||||
|  | ||||
| 	return resultF() | ||||
| } | ||||
|  | ||||
| type switchCase[T comparable, R any] struct { | ||||
| 	predicate T | ||||
| 	result    R | ||||
| @@ -50,6 +96,7 @@ type switchCase[T comparable, R any] struct { | ||||
| } | ||||
|  | ||||
| // Switch is a pure functional switch/case/default statement. | ||||
| // Play: https://go.dev/play/p/TGbKUMAeRUd | ||||
| func Switch[T comparable, R any](predicate T) *switchCase[T, R] { | ||||
| 	var result R | ||||
|  | ||||
| @@ -61,6 +108,7 @@ func Switch[T comparable, R any](predicate T) *switchCase[T, R] { | ||||
| } | ||||
|  | ||||
| // Case. | ||||
| // Play: https://go.dev/play/p/TGbKUMAeRUd | ||||
| func (s *switchCase[T, R]) Case(val T, result R) *switchCase[T, R] { | ||||
| 	if !s.done && s.predicate == val { | ||||
| 		s.result = result | ||||
| @@ -71,6 +119,7 @@ func (s *switchCase[T, R]) Case(val T, result R) *switchCase[T, R] { | ||||
| } | ||||
|  | ||||
| // CaseF. | ||||
| // Play: https://go.dev/play/p/TGbKUMAeRUd | ||||
| func (s *switchCase[T, R]) CaseF(val T, cb func() R) *switchCase[T, R] { | ||||
| 	if !s.done && s.predicate == val { | ||||
| 		s.result = cb() | ||||
| @@ -81,6 +130,7 @@ func (s *switchCase[T, R]) CaseF(val T, cb func() R) *switchCase[T, R] { | ||||
| } | ||||
|  | ||||
| // Default. | ||||
| // Play: https://go.dev/play/p/TGbKUMAeRUd | ||||
| func (s *switchCase[T, R]) Default(result R) R { | ||||
| 	if !s.done { | ||||
| 		s.result = result | ||||
| @@ -90,6 +140,7 @@ func (s *switchCase[T, R]) Default(result R) R { | ||||
| } | ||||
|  | ||||
| // DefaultF. | ||||
| // Play: https://go.dev/play/p/TGbKUMAeRUd | ||||
| func (s *switchCase[T, R]) DefaultF(cb func() R) R { | ||||
| 	if !s.done { | ||||
| 		s.result = cb() | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/samber/lo/docker-compose.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/samber/lo/docker-compose.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,8 +2,8 @@ version: '3' | ||||
|  | ||||
| services: | ||||
|   dev: | ||||
|     build: . | ||||
|     image: golang:1.18-bullseye | ||||
|     volumes: | ||||
|       - ./:/go/src/github.com/samber/lo | ||||
|     working_dir: /go/src/github.com/samber/lo | ||||
|     command: bash -c 'make tools ; make watch-test' | ||||
|     command: make watch-test | ||||
|   | ||||
							
								
								
									
										65
									
								
								vendor/github.com/samber/lo/drop.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/samber/lo/drop.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,65 +0,0 @@ | ||||
| package lo | ||||
|  | ||||
| //Drop drops n elements from the beginning of a slice or array. | ||||
| func Drop[T any](collection []T, n int) []T { | ||||
| 	if len(collection) <= n { | ||||
| 		return make([]T, 0) | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, len(collection)-n) | ||||
| 	for i := n; i < len(collection); i++ { | ||||
| 		result[i-n] = collection[i] | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| //DropWhile drops elements from the beginning of a slice or array while the predicate returns true. | ||||
| func DropWhile[T any](collection []T, predicate func(T) bool) []T { | ||||
| 	i := 0 | ||||
| 	for ; i < len(collection); i++ { | ||||
| 		if !predicate(collection[i]) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, len(collection)-i) | ||||
|  | ||||
| 	for j := 0; i < len(collection); i, j = i+1, j+1 { | ||||
| 		result[j] = collection[i] | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| //DropRight drops n elements from the end of a slice or array. | ||||
| func DropRight[T any](collection []T, n int) []T { | ||||
| 	if len(collection) <= n { | ||||
| 		return make([]T, 0) | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, len(collection)-n) | ||||
| 	for i := len(collection) - 1 - n; i != 0; i-- { | ||||
| 		result[i] = collection[i] | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| //DropRightWhile drops elements from the end of a slice or array while the predicate returns true. | ||||
| func DropRightWhile[T any](collection []T, predicate func(T) bool) []T { | ||||
| 	i := len(collection) - 1 | ||||
| 	for ; i >= 0; i-- { | ||||
| 		if !predicate(collection[i]) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, i+1) | ||||
|  | ||||
| 	for ; i >= 0; i-- { | ||||
| 		result[i] = collection[i] | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
							
								
								
									
										354
									
								
								vendor/github.com/samber/lo/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								vendor/github.com/samber/lo/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | ||||
| package lo | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| // Validate is a helper that creates an error when a condition is not met. | ||||
| // Play: https://go.dev/play/p/vPyh51XpCBt | ||||
| func Validate(ok bool, format string, args ...any) error { | ||||
| 	if !ok { | ||||
| 		return fmt.Errorf(fmt.Sprintf(format, args...)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { | ||||
| 	if len(msgAndArgs) == 1 { | ||||
| 		if msgAsStr, ok := msgAndArgs[0].(string); ok { | ||||
| 			return msgAsStr | ||||
| 		} | ||||
| 		return fmt.Sprintf("%+v", msgAndArgs[0]) | ||||
| 	} | ||||
| 	if len(msgAndArgs) > 1 { | ||||
| 		return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // must panics if err is error or false. | ||||
| func must(err any, messageArgs ...interface{}) { | ||||
| 	if err == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	switch e := err.(type) { | ||||
| 	case bool: | ||||
| 		if !e { | ||||
| 			message := messageFromMsgAndArgs(messageArgs...) | ||||
| 			if message == "" { | ||||
| 				message = "not ok" | ||||
| 			} | ||||
|  | ||||
| 			panic(message) | ||||
| 		} | ||||
|  | ||||
| 	case error: | ||||
| 		message := messageFromMsgAndArgs(messageArgs...) | ||||
| 		if message != "" { | ||||
| 			panic(message + ": " + e.Error()) | ||||
| 		} else { | ||||
| 			panic(e.Error()) | ||||
| 		} | ||||
|  | ||||
| 	default: | ||||
| 		panic("must: invalid err type '" + reflect.TypeOf(err).Name() + "', should either be a bool or an error") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Must is a helper that wraps a call to a function returning a value and an error | ||||
| // and panics if err is error or false. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must[T any](val T, err any, messageArgs ...interface{}) T { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val | ||||
| } | ||||
|  | ||||
| // Must0 has the same behavior than Must, but callback returns no variable. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must0(err any, messageArgs ...interface{}) { | ||||
| 	must(err, messageArgs...) | ||||
| } | ||||
|  | ||||
| // Must1 is an alias to Must | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must1[T any](val T, err any, messageArgs ...interface{}) T { | ||||
| 	return Must(val, err, messageArgs...) | ||||
| } | ||||
|  | ||||
| // Must2 has the same behavior than Must, but callback returns 2 variables. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must2[T1 any, T2 any](val1 T1, val2 T2, err any, messageArgs ...interface{}) (T1, T2) { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val1, val2 | ||||
| } | ||||
|  | ||||
| // Must3 has the same behavior than Must, but callback returns 3 variables. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must3[T1 any, T2 any, T3 any](val1 T1, val2 T2, val3 T3, err any, messageArgs ...interface{}) (T1, T2, T3) { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val1, val2, val3 | ||||
| } | ||||
|  | ||||
| // Must4 has the same behavior than Must, but callback returns 4 variables. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must4[T1 any, T2 any, T3 any, T4 any](val1 T1, val2 T2, val3 T3, val4 T4, err any, messageArgs ...interface{}) (T1, T2, T3, T4) { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val1, val2, val3, val4 | ||||
| } | ||||
|  | ||||
| // Must5 has the same behavior than Must, but callback returns 5 variables. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must5[T1 any, T2 any, T3 any, T4 any, T5 any](val1 T1, val2 T2, val3 T3, val4 T4, val5 T5, err any, messageArgs ...interface{}) (T1, T2, T3, T4, T5) { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val1, val2, val3, val4, val5 | ||||
| } | ||||
|  | ||||
| // Must6 has the same behavior than Must, but callback returns 6 variables. | ||||
| // Play: https://go.dev/play/p/TMoWrRp3DyC | ||||
| func Must6[T1 any, T2 any, T3 any, T4 any, T5 any, T6 any](val1 T1, val2 T2, val3 T3, val4 T4, val5 T5, val6 T6, err any, messageArgs ...interface{}) (T1, T2, T3, T4, T5, T6) { | ||||
| 	must(err, messageArgs...) | ||||
| 	return val1, val2, val3, val4, val5, val6 | ||||
| } | ||||
|  | ||||
| // Try calls the function and return false in case of error. | ||||
| func Try(callback func() error) (ok bool) { | ||||
| 	ok = true | ||||
|  | ||||
| 	defer func() { | ||||
| 		if r := recover(); r != nil { | ||||
| 			ok = false | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err := callback() | ||||
| 	if err != nil { | ||||
| 		ok = false | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Try0 has the same behavior than Try, but callback returns no variable. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try0(callback func()) bool { | ||||
| 	return Try(func() error { | ||||
| 		callback() | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Try1 is an alias to Try. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try1(callback func() error) bool { | ||||
| 	return Try(callback) | ||||
| } | ||||
|  | ||||
| // Try2 has the same behavior than Try, but callback returns 2 variables. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try2[T any](callback func() (T, error)) bool { | ||||
| 	return Try(func() error { | ||||
| 		_, err := callback() | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Try3 has the same behavior than Try, but callback returns 3 variables. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try3[T, R any](callback func() (T, R, error)) bool { | ||||
| 	return Try(func() error { | ||||
| 		_, _, err := callback() | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Try4 has the same behavior than Try, but callback returns 4 variables. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try4[T, R, S any](callback func() (T, R, S, error)) bool { | ||||
| 	return Try(func() error { | ||||
| 		_, _, _, err := callback() | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Try5 has the same behavior than Try, but callback returns 5 variables. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try5[T, R, S, Q any](callback func() (T, R, S, Q, error)) bool { | ||||
| 	return Try(func() error { | ||||
| 		_, _, _, _, err := callback() | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Try6 has the same behavior than Try, but callback returns 6 variables. | ||||
| // Play: https://go.dev/play/p/mTyyWUvn9u4 | ||||
| func Try6[T, R, S, Q, U any](callback func() (T, R, S, Q, U, error)) bool { | ||||
| 	return Try(func() error { | ||||
| 		_, _, _, _, _, err := callback() | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // TryOr has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr[A any](callback func() (A, error), fallbackA A) (A, bool) { | ||||
| 	return TryOr1(callback, fallbackA) | ||||
| } | ||||
|  | ||||
| // TryOr1 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr1[A any](callback func() (A, error), fallbackA A) (A, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, ok | ||||
| } | ||||
|  | ||||
| // TryOr2 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr2[A any, B any](callback func() (A, B, error), fallbackA A, fallbackB B) (A, B, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, b, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			fallbackB = b | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, fallbackB, ok | ||||
| } | ||||
|  | ||||
| // TryOr3 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr3[A any, B any, C any](callback func() (A, B, C, error), fallbackA A, fallbackB B, fallbackC C) (A, B, C, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, b, c, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			fallbackB = b | ||||
| 			fallbackC = c | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, fallbackB, fallbackC, ok | ||||
| } | ||||
|  | ||||
| // TryOr4 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr4[A any, B any, C any, D any](callback func() (A, B, C, D, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D) (A, B, C, D, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, b, c, d, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			fallbackB = b | ||||
| 			fallbackC = c | ||||
| 			fallbackD = d | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, fallbackB, fallbackC, fallbackD, ok | ||||
| } | ||||
|  | ||||
| // TryOr5 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr5[A any, B any, C any, D any, E any](callback func() (A, B, C, D, E, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D, fallbackE E) (A, B, C, D, E, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, b, c, d, e, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			fallbackB = b | ||||
| 			fallbackC = c | ||||
| 			fallbackD = d | ||||
| 			fallbackE = e | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, fallbackB, fallbackC, fallbackD, fallbackE, ok | ||||
| } | ||||
|  | ||||
| // TryOr6 has the same behavior than Must, but returns a default value in case of error. | ||||
| // Play: https://go.dev/play/p/B4F7Wg2Zh9X | ||||
| func TryOr6[A any, B any, C any, D any, E any, F any](callback func() (A, B, C, D, E, F, error), fallbackA A, fallbackB B, fallbackC C, fallbackD D, fallbackE E, fallbackF F) (A, B, C, D, E, F, bool) { | ||||
| 	ok := false | ||||
|  | ||||
| 	Try0(func() { | ||||
| 		a, b, c, d, e, f, err := callback() | ||||
| 		if err == nil { | ||||
| 			fallbackA = a | ||||
| 			fallbackB = b | ||||
| 			fallbackC = c | ||||
| 			fallbackD = d | ||||
| 			fallbackE = e | ||||
| 			fallbackF = f | ||||
| 			ok = true | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return fallbackA, fallbackB, fallbackC, fallbackD, fallbackE, fallbackF, ok | ||||
| } | ||||
|  | ||||
| // TryWithErrorValue has the same behavior than Try, but also returns value passed to panic. | ||||
| // Play: https://go.dev/play/p/Kc7afQIT2Fs | ||||
| func TryWithErrorValue(callback func() error) (errorValue any, ok bool) { | ||||
| 	ok = true | ||||
|  | ||||
| 	defer func() { | ||||
| 		if r := recover(); r != nil { | ||||
| 			ok = false | ||||
| 			errorValue = r | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	err := callback() | ||||
| 	if err != nil { | ||||
| 		ok = false | ||||
| 		errorValue = err | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // TryCatch has the same behavior than Try, but calls the catch function in case of error. | ||||
| // Play: https://go.dev/play/p/PnOON-EqBiU | ||||
| func TryCatch(callback func() error, catch func()) { | ||||
| 	if !Try(callback) { | ||||
| 		catch() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // TryCatchWithErrorValue has the same behavior than TryWithErrorValue, but calls the catch function in case of error. | ||||
| // Play: https://go.dev/play/p/8Pc9gwX_GZO | ||||
| func TryCatchWithErrorValue(callback func() error, catch func(any)) { | ||||
| 	if err, ok := TryWithErrorValue(callback); !ok { | ||||
| 		catch(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ErrorsAs is a shortcut for errors.As(err, &&T). | ||||
| // Play: https://go.dev/play/p/8wk5rH8UfrE | ||||
| func ErrorsAs[T error](err error) (T, bool) { | ||||
| 	var t T | ||||
| 	ok := errors.As(err, &t) | ||||
| 	return t, ok | ||||
| } | ||||
							
								
								
									
										247
									
								
								vendor/github.com/samber/lo/find.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										247
									
								
								vendor/github.com/samber/lo/find.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ package lo | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"math" | ||||
|  | ||||
| 	"golang.org/x/exp/constraints" | ||||
| ) | ||||
|  | ||||
| @@ -21,7 +21,7 @@ func IndexOf[T comparable](collection []T, element T) int { | ||||
| 	return -1 | ||||
| } | ||||
|  | ||||
| // IndexOf returns the index at which the last occurrence of a value is found in an array or return -1 | ||||
| // LastIndexOf returns the index at which the last occurrence of a value is found in an array or return -1 | ||||
| // if the value cannot be found. | ||||
| func LastIndexOf[T comparable](collection []T, element T) int { | ||||
| 	length := len(collection) | ||||
| @@ -47,6 +47,179 @@ func Find[T any](collection []T, predicate func(T) bool) (T, bool) { | ||||
| 	return result, false | ||||
| } | ||||
|  | ||||
| // FindIndexOf searches an element in a slice based on a predicate and returns the index and true. | ||||
| // It returns -1 and false if the element is not found. | ||||
| func FindIndexOf[T any](collection []T, predicate func(T) bool) (T, int, bool) { | ||||
| 	for i, item := range collection { | ||||
| 		if predicate(item) { | ||||
| 			return item, i, true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var result T | ||||
| 	return result, -1, false | ||||
| } | ||||
|  | ||||
| // FindLastIndexOf searches last element in a slice based on a predicate and returns the index and true. | ||||
| // It returns -1 and false if the element is not found. | ||||
| func FindLastIndexOf[T any](collection []T, predicate func(T) bool) (T, int, bool) { | ||||
| 	length := len(collection) | ||||
|  | ||||
| 	for i := length - 1; i >= 0; i-- { | ||||
| 		if predicate(collection[i]) { | ||||
| 			return collection[i], i, true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var result T | ||||
| 	return result, -1, false | ||||
| } | ||||
|  | ||||
| // FindOrElse search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise. | ||||
| func FindOrElse[T any](collection []T, fallback T, predicate func(T) bool) T { | ||||
| 	for _, item := range collection { | ||||
| 		if predicate(item) { | ||||
| 			return item | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fallback | ||||
| } | ||||
|  | ||||
| // FindKey returns the key of the first value matching. | ||||
| func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) { | ||||
| 	for k, v := range object { | ||||
| 		if v == value { | ||||
| 			return k, true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return Empty[K](), false | ||||
| } | ||||
|  | ||||
| // FindKeyBy returns the key of the first element predicate returns truthy for. | ||||
| func FindKeyBy[K comparable, V any](object map[K]V, predicate func(K, V) bool) (K, bool) { | ||||
| 	for k, v := range object { | ||||
| 		if predicate(k, v) { | ||||
| 			return k, true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return Empty[K](), false | ||||
| } | ||||
|  | ||||
| // FindUniques returns a slice with all the unique elements of the collection. | ||||
| // The order of result values is determined by the order they occur in the collection. | ||||
| func FindUniques[T comparable](collection []T) []T { | ||||
| 	isDupl := make(map[T]bool, len(collection)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		duplicated, ok := isDupl[item] | ||||
| 		if !ok { | ||||
| 			isDupl[item] = false | ||||
| 		} else if !duplicated { | ||||
| 			isDupl[item] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-len(isDupl)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		if duplicated := isDupl[item]; !duplicated { | ||||
| 			result = append(result, item) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FindUniquesBy returns a slice with all the unique elements of the collection. | ||||
| // The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is | ||||
| // invoked for each element in array to generate the criterion by which uniqueness is computed. | ||||
| func FindUniquesBy[T any, U comparable](collection []T, iteratee func(T) U) []T { | ||||
| 	isDupl := make(map[U]bool, len(collection)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		key := iteratee(item) | ||||
|  | ||||
| 		duplicated, ok := isDupl[key] | ||||
| 		if !ok { | ||||
| 			isDupl[key] = false | ||||
| 		} else if !duplicated { | ||||
| 			isDupl[key] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-len(isDupl)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		key := iteratee(item) | ||||
|  | ||||
| 		if duplicated := isDupl[key]; !duplicated { | ||||
| 			result = append(result, item) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FindDuplicates returns a slice with the first occurence of each duplicated elements of the collection. | ||||
| // The order of result values is determined by the order they occur in the collection. | ||||
| func FindDuplicates[T comparable](collection []T) []T { | ||||
| 	isDupl := make(map[T]bool, len(collection)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		duplicated, ok := isDupl[item] | ||||
| 		if !ok { | ||||
| 			isDupl[item] = false | ||||
| 		} else if !duplicated { | ||||
| 			isDupl[item] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-len(isDupl)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		if duplicated := isDupl[item]; duplicated { | ||||
| 			result = append(result, item) | ||||
| 			isDupl[item] = false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FindDuplicatesBy returns a slice with the first occurence of each duplicated elements of the collection. | ||||
| // The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is | ||||
| // invoked for each element in array to generate the criterion by which uniqueness is computed. | ||||
| func FindDuplicatesBy[T any, U comparable](collection []T, iteratee func(T) U) []T { | ||||
| 	isDupl := make(map[U]bool, len(collection)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		key := iteratee(item) | ||||
|  | ||||
| 		duplicated, ok := isDupl[key] | ||||
| 		if !ok { | ||||
| 			isDupl[key] = false | ||||
| 		} else if !duplicated { | ||||
| 			isDupl[key] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-len(isDupl)) | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		key := iteratee(item) | ||||
|  | ||||
| 		if duplicated := isDupl[key]; duplicated { | ||||
| 			result = append(result, item) | ||||
| 			isDupl[key] = false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Min search the minimum value of a collection. | ||||
| func Min[T constraints.Ordered](collection []T) T { | ||||
| 	var min T | ||||
| @@ -60,7 +233,6 @@ func Min[T constraints.Ordered](collection []T) T { | ||||
| 	for i := 1; i < len(collection); i++ { | ||||
| 		item := collection[i] | ||||
|  | ||||
| 		// if item.Less(min) { | ||||
| 		if item < min { | ||||
| 			min = item | ||||
| 		} | ||||
| @@ -69,7 +241,29 @@ func Min[T constraints.Ordered](collection []T) T { | ||||
| 	return min | ||||
| } | ||||
|  | ||||
| // Max search the maximum value of a collection. | ||||
| // MinBy search the minimum value of a collection using the given comparison function. | ||||
| // If several values of the collection are equal to the smallest value, returns the first such value. | ||||
| func MinBy[T any](collection []T, comparison func(T, T) bool) T { | ||||
| 	var min T | ||||
|  | ||||
| 	if len(collection) == 0 { | ||||
| 		return min | ||||
| 	} | ||||
|  | ||||
| 	min = collection[0] | ||||
|  | ||||
| 	for i := 1; i < len(collection); i++ { | ||||
| 		item := collection[i] | ||||
|  | ||||
| 		if comparison(item, min) { | ||||
| 			min = item | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return min | ||||
| } | ||||
|  | ||||
| // Max searches the maximum value of a collection. | ||||
| func Max[T constraints.Ordered](collection []T) T { | ||||
| 	var max T | ||||
|  | ||||
| @@ -90,6 +284,28 @@ func Max[T constraints.Ordered](collection []T) T { | ||||
| 	return max | ||||
| } | ||||
|  | ||||
| // MaxBy search the maximum value of a collection using the given comparison function. | ||||
| // If several values of the collection are equal to the greatest value, returns the first such value. | ||||
| func MaxBy[T any](collection []T, comparison func(T, T) bool) T { | ||||
| 	var max T | ||||
|  | ||||
| 	if len(collection) == 0 { | ||||
| 		return max | ||||
| 	} | ||||
|  | ||||
| 	max = collection[0] | ||||
|  | ||||
| 	for i := 1; i < len(collection); i++ { | ||||
| 		item := collection[i] | ||||
|  | ||||
| 		if comparison(item, max) { | ||||
| 			max = item | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return max | ||||
| } | ||||
|  | ||||
| // Last returns the last element of a collection or error if empty. | ||||
| func Last[T any](collection []T) (T, error) { | ||||
| 	length := len(collection) | ||||
| @@ -104,19 +320,18 @@ func Last[T any](collection []T) (T, error) { | ||||
|  | ||||
| // Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element | ||||
| // from the end is returned. An error is returned when nth is out of slice bounds. | ||||
| func Nth[T any](collection []T, nth int) (T, error) { | ||||
| 	if int(math.Abs(float64(nth))) >= len(collection) { | ||||
| func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) { | ||||
| 	n := int(nth) | ||||
| 	l := len(collection) | ||||
| 	if n >= l || -n > l { | ||||
| 		var t T | ||||
| 		return t, fmt.Errorf("nth: %d out of slice bounds", nth) | ||||
| 		return t, fmt.Errorf("nth: %d out of slice bounds", n) | ||||
| 	} | ||||
|  | ||||
| 	length := len(collection) | ||||
|  | ||||
| 	if nth >= 0 { | ||||
| 		return collection[nth], nil | ||||
| 	if n >= 0 { | ||||
| 		return collection[n], nil | ||||
| 	} | ||||
|  | ||||
| 	return collection[length+nth], nil | ||||
| 	return collection[l+n], nil | ||||
| } | ||||
|  | ||||
| // Sample returns a random item from collection. | ||||
| @@ -133,11 +348,7 @@ func Sample[T any](collection []T) T { | ||||
| func Samples[T any](collection []T, count int) []T { | ||||
| 	size := len(collection) | ||||
|  | ||||
| 	// put values into a map, for faster deletion | ||||
| 	cOpy := make([]T, 0, size) | ||||
| 	for _, v := range collection { | ||||
| 		cOpy = append(cOpy, v) | ||||
| 	} | ||||
| 	cOpy := append([]T{}, collection...) | ||||
|  | ||||
| 	results := []T{} | ||||
|  | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/samber/lo/func.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/samber/lo/func.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| package lo | ||||
|  | ||||
| // Partial returns new function that, when called, has its first argument set to the provided value. | ||||
| func Partial[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R { | ||||
| 	return func(t2 T2) R { | ||||
| 		return f(arg1, t2) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										73
									
								
								vendor/github.com/samber/lo/intersect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/samber/lo/intersect.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,7 +22,7 @@ func ContainsBy[T any](collection []T, predicate func(T) bool) bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Every returns true if all elements of a subset are contained into a collection. | ||||
| // Every returns true if all elements of a subset are contained into a collection or if the subset is empty. | ||||
| func Every[T comparable](collection []T, subset []T) bool { | ||||
| 	for _, elem := range subset { | ||||
| 		if !Contains(collection, elem) { | ||||
| @@ -33,7 +33,19 @@ func Every[T comparable](collection []T, subset []T) bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // EveryBy returns true if the predicate returns true for all of the elements in the collection or if the collection is empty. | ||||
| func EveryBy[V any](collection []V, predicate func(V) bool) bool { | ||||
| 	for _, v := range collection { | ||||
| 		if !predicate(v) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Some returns true if at least 1 element of a subset is contained into a collection. | ||||
| // If the subset is empty Some returns false. | ||||
| func Some[T comparable](collection []T, subset []T) bool { | ||||
| 	for _, elem := range subset { | ||||
| 		if Contains(collection, elem) { | ||||
| @@ -44,6 +56,40 @@ func Some[T comparable](collection []T, subset []T) bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // SomeBy returns true if the predicate returns true for any of the elements in the collection. | ||||
| // If the collection is empty SomeBy returns false. | ||||
| func SomeBy[V any](collection []V, predicate func(V) bool) bool { | ||||
| 	for _, v := range collection { | ||||
| 		if predicate(v) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // None returns true if no element of a subset are contained into a collection or if the subset is empty. | ||||
| func None[V comparable](collection []V, subset []V) bool { | ||||
| 	for _, elem := range subset { | ||||
| 		if Contains(collection, elem) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // NoneBy returns true if the predicate returns true for none of the elements in the collection or if the collection is empty. | ||||
| func NoneBy[V any](collection []V, predicate func(V) bool) bool { | ||||
| 	for _, v := range collection { | ||||
| 		if predicate(v) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // Intersect returns the intersection between two collections. | ||||
| func Intersect[T comparable](list1 []T, list2 []T) []T { | ||||
| 	result := []T{} | ||||
| @@ -129,3 +175,28 @@ func Union[T comparable](list1 []T, list2 []T) []T { | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Without returns slice excluding all given values. | ||||
| func Without[T comparable](collection []T, exclude ...T) []T { | ||||
| 	result := make([]T, 0, len(collection)) | ||||
| 	for _, e := range collection { | ||||
| 		if !Contains(exclude, e) { | ||||
| 			result = append(result, e) | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // WithoutEmpty returns slice excluding empty values. | ||||
| func WithoutEmpty[T comparable](collection []T) []T { | ||||
| 	var empty T | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)) | ||||
| 	for _, e := range collection { | ||||
| 		if e != empty { | ||||
| 			result = append(result, e) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|   | ||||
							
								
								
									
										134
									
								
								vendor/github.com/samber/lo/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										134
									
								
								vendor/github.com/samber/lo/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,10 +1,11 @@ | ||||
| package lo | ||||
|  | ||||
| // Keys creates an array of the map keys. | ||||
| // Play: https://go.dev/play/p/Uu11fHASqrU | ||||
| func Keys[K comparable, V any](in map[K]V) []K { | ||||
| 	result := make([]K, 0, len(in)) | ||||
|  | ||||
| 	for k, _ := range in { | ||||
| 	for k := range in { | ||||
| 		result = append(result, k) | ||||
| 	} | ||||
|  | ||||
| @@ -12,6 +13,7 @@ func Keys[K comparable, V any](in map[K]V) []K { | ||||
| } | ||||
|  | ||||
| // Values creates an array of the map values. | ||||
| // Play: https://go.dev/play/p/nnRTQkzQfF6 | ||||
| func Values[K comparable, V any](in map[K]V) []V { | ||||
| 	result := make([]V, 0, len(in)) | ||||
|  | ||||
| @@ -22,7 +24,80 @@ func Values[K comparable, V any](in map[K]V) []V { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // PickBy returns same map type filtered by given predicate. | ||||
| // Play: https://go.dev/play/p/kdg8GR_QMmf | ||||
| func PickBy[K comparable, V any](in map[K]V, predicate func(K, V) bool) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if predicate(k, v) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // PickByKeys returns same map type filtered by given keys. | ||||
| // Play: https://go.dev/play/p/R1imbuci9qU | ||||
| func PickByKeys[K comparable, V any](in map[K]V, keys []K) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if Contains(keys, k) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // PickByValues returns same map type filtered by given values. | ||||
| // Play: https://go.dev/play/p/1zdzSvbfsJc | ||||
| func PickByValues[K comparable, V comparable](in map[K]V, values []V) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if Contains(values, v) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // OmitBy returns same map type filtered by given predicate. | ||||
| // Play: https://go.dev/play/p/EtBsR43bdsd | ||||
| func OmitBy[K comparable, V any](in map[K]V, predicate func(K, V) bool) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if !predicate(k, v) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // OmitByKeys returns same map type filtered by given keys. | ||||
| // Play: https://go.dev/play/p/t1QjCrs-ysk | ||||
| func OmitByKeys[K comparable, V any](in map[K]V, keys []K) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if !Contains(keys, k) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // OmitByValues returns same map type filtered by given values. | ||||
| // Play: https://go.dev/play/p/9UYZi-hrs8j | ||||
| func OmitByValues[K comparable, V comparable](in map[K]V, values []V) map[K]V { | ||||
| 	r := map[K]V{} | ||||
| 	for k, v := range in { | ||||
| 		if !Contains(values, v) { | ||||
| 			r[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // Entries transforms a map into array of key/value pairs. | ||||
| // Play: | ||||
| func Entries[K comparable, V any](in map[K]V) []Entry[K, V] { | ||||
| 	entries := make([]Entry[K, V], 0, len(in)) | ||||
|  | ||||
| @@ -36,7 +111,15 @@ func Entries[K comparable, V any](in map[K]V) []Entry[K, V] { | ||||
| 	return entries | ||||
| } | ||||
|  | ||||
| // ToPairs transforms a map into array of key/value pairs. | ||||
| // Alias of Entries(). | ||||
| // Play: https://go.dev/play/p/3Dhgx46gawJ | ||||
| func ToPairs[K comparable, V any](in map[K]V) []Entry[K, V] { | ||||
| 	return Entries(in) | ||||
| } | ||||
|  | ||||
| // FromEntries transforms an array of key/value pairs into a map. | ||||
| // Play: https://go.dev/play/p/oIr5KHFGCEN | ||||
| func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V { | ||||
| 	out := map[K]V{} | ||||
|  | ||||
| @@ -47,7 +130,29 @@ func FromEntries[K comparable, V any](entries []Entry[K, V]) map[K]V { | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // FromPairs transforms an array of key/value pairs into a map. | ||||
| // Alias of FromEntries(). | ||||
| // Play: https://go.dev/play/p/oIr5KHFGCEN | ||||
| func FromPairs[K comparable, V any](entries []Entry[K, V]) map[K]V { | ||||
| 	return FromEntries(entries) | ||||
| } | ||||
|  | ||||
| // Invert creates a map composed of the inverted keys and values. If map | ||||
| // contains duplicate values, subsequent values overwrite property assignments | ||||
| // of previous values. | ||||
| // Play: https://go.dev/play/p/rFQ4rak6iA1 | ||||
| func Invert[K comparable, V comparable](in map[K]V) map[V]K { | ||||
| 	out := map[V]K{} | ||||
|  | ||||
| 	for k, v := range in { | ||||
| 		out[v] = k | ||||
| 	} | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // Assign merges multiple maps from left to right. | ||||
| // Play: https://go.dev/play/p/VhwfJOyxf5o | ||||
| func Assign[K comparable, V any](maps ...map[K]V) map[K]V { | ||||
| 	out := map[K]V{} | ||||
|  | ||||
| @@ -60,7 +165,20 @@ func Assign[K comparable, V any](maps ...map[K]V) map[K]V { | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // MapKeys manipulates a map keys and transforms it to a map of another type. | ||||
| // Play: https://go.dev/play/p/9_4WPIqOetJ | ||||
| func MapKeys[K comparable, V any, R comparable](in map[K]V, iteratee func(V, K) R) map[R]V { | ||||
| 	result := map[R]V{} | ||||
|  | ||||
| 	for k, v := range in { | ||||
| 		result[iteratee(v, k)] = v | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // MapValues manipulates a map values and transforms it to a map of another type. | ||||
| // Play: https://go.dev/play/p/T_8xAfvcf0W | ||||
| func MapValues[K comparable, V any, R any](in map[K]V, iteratee func(V, K) R) map[K]R { | ||||
| 	result := map[K]R{} | ||||
|  | ||||
| @@ -69,4 +187,16 @@ func MapValues[K comparable, V any, R any](in map[K]V, iteratee func(V, K) R) ma | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
| } | ||||
|  | ||||
| // MapToSlice transforms a map into a slice based on specific iteratee | ||||
| // Play: https://go.dev/play/p/ZuiCZpDt6LD | ||||
| func MapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(K, V) R) []R { | ||||
| 	result := make([]R, 0, len(in)) | ||||
|  | ||||
| 	for k, v := range in { | ||||
| 		result = append(result, iteratee(k, v)) | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|   | ||||
							
								
								
									
										24
									
								
								vendor/github.com/samber/lo/util.go → vendor/github.com/samber/lo/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/samber/lo/util.go → vendor/github.com/samber/lo/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ package lo | ||||
| import "golang.org/x/exp/constraints" | ||||
| 
 | ||||
| // Range creates an array of numbers (positive and/or negative) with given length. | ||||
| // Play: https://go.dev/play/p/0r6VimXAi9H | ||||
| func Range(elementNum int) []int { | ||||
| 	length := If(elementNum < 0, -elementNum).Else(elementNum) | ||||
| 	result := make([]int, length) | ||||
| @@ -14,6 +15,7 @@ func Range(elementNum int) []int { | ||||
| } | ||||
| 
 | ||||
| // RangeFrom creates an array of numbers from start with specified length. | ||||
| // Play: https://go.dev/play/p/0r6VimXAi9H | ||||
| func RangeFrom[T constraints.Integer | constraints.Float](start T, elementNum int) []T { | ||||
| 	length := If(elementNum < 0, -elementNum).Else(elementNum) | ||||
| 	result := make([]T, length) | ||||
| @@ -26,6 +28,7 @@ func RangeFrom[T constraints.Integer | constraints.Float](start T, elementNum in | ||||
| 
 | ||||
| // RangeWithSteps creates an array of numbers (positive and/or negative) progressing from start up to, but not including end. | ||||
| // step set to zero will return empty array. | ||||
| // Play: https://go.dev/play/p/0r6VimXAi9H | ||||
| func RangeWithSteps[T constraints.Integer | constraints.Float](start, end, step T) []T { | ||||
| 	result := []T{} | ||||
| 	if start == end || step == 0 { | ||||
| @@ -48,3 +51,24 @@ func RangeWithSteps[T constraints.Integer | constraints.Float](start, end, step | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| // Clamp clamps number within the inclusive lower and upper bounds. | ||||
| // Play: https://go.dev/play/p/RU4lJNC2hlI | ||||
| func Clamp[T constraints.Ordered](value T, min T, max T) T { | ||||
| 	if value < min { | ||||
| 		return min | ||||
| 	} else if value > max { | ||||
| 		return max | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
| 
 | ||||
| // SumBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 0 is returned. | ||||
| // Play: https://go.dev/play/p/Dz_a_7jN_ca | ||||
| func SumBy[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(T) R) R { | ||||
| 	var sum R = 0 | ||||
| 	for _, item := range collection { | ||||
| 		sum = sum + iteratee(item) | ||||
| 	} | ||||
| 	return sum | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/github.com/samber/lo/pointers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/samber/lo/pointers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | ||||
| package lo | ||||
|  | ||||
| // ToPtr returns a pointer copy of value. | ||||
| func ToPtr[T any](x T) *T { | ||||
| 	return &x | ||||
| } | ||||
|  | ||||
| // ToPtr returns a slice of pointer copy of value. | ||||
| func ToSlicePtr[T any](collection []T) []*T { | ||||
| 	return Map(collection, func (x T, _ int) *T { | ||||
| 		return &x | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // Empty returns an empty value. | ||||
| func Empty[T any]() T { | ||||
| 	var t T | ||||
| 	return t | ||||
| } | ||||
							
								
								
									
										89
									
								
								vendor/github.com/samber/lo/retry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										89
									
								
								vendor/github.com/samber/lo/retry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,68 @@ | ||||
| package lo | ||||
|  | ||||
| // Attempt invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a sucessfull response is returned. | ||||
| import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type debounce struct { | ||||
| 	after     time.Duration | ||||
| 	mu        *sync.Mutex | ||||
| 	timer     *time.Timer | ||||
| 	done      bool | ||||
| 	callbacks []func() | ||||
| } | ||||
|  | ||||
| func (d *debounce) reset() *debounce { | ||||
| 	d.mu.Lock() | ||||
| 	defer d.mu.Unlock() | ||||
|  | ||||
| 	if d.done { | ||||
| 		return d | ||||
| 	} | ||||
|  | ||||
| 	if d.timer != nil { | ||||
| 		d.timer.Stop() | ||||
| 	} | ||||
|  | ||||
| 	d.timer = time.AfterFunc(d.after, func() { | ||||
| 		for _, f := range d.callbacks { | ||||
| 			f() | ||||
| 		} | ||||
| 	}) | ||||
| 	return d | ||||
| } | ||||
|  | ||||
| func (d *debounce) cancel() { | ||||
| 	d.mu.Lock() | ||||
| 	defer d.mu.Unlock() | ||||
|  | ||||
| 	if d.timer != nil { | ||||
| 		d.timer.Stop() | ||||
| 		d.timer = nil | ||||
| 	} | ||||
|  | ||||
| 	d.done = true | ||||
| } | ||||
|  | ||||
| // NewDebounce creates a debounced instance that delays invoking functions given until after wait milliseconds have elapsed. | ||||
| // Play: https://go.dev/play/p/mz32VMK2nqe | ||||
| func NewDebounce(duration time.Duration, f ...func()) (func(), func()) { | ||||
| 	d := &debounce{ | ||||
| 		after:     duration, | ||||
| 		mu:        new(sync.Mutex), | ||||
| 		timer:     nil, | ||||
| 		done:      false, | ||||
| 		callbacks: f, | ||||
| 	} | ||||
|  | ||||
| 	return func() { | ||||
| 		d.reset() | ||||
| 	}, d.cancel | ||||
| } | ||||
|  | ||||
| // Attempt invokes a function N times until it returns valid output. Returning either the caught error or nil. When first argument is less than `1`, the function runs until a successful response is returned. | ||||
| // Play: https://go.dev/play/p/3ggJZ2ZKcMj | ||||
| func Attempt(maxIteration int, f func(int) error) (int, error) { | ||||
| 	var err error | ||||
|  | ||||
| @@ -15,5 +77,28 @@ func Attempt(maxIteration int, f func(int) error) (int, error) { | ||||
| 	return maxIteration, err | ||||
| } | ||||
|  | ||||
| // AttemptWithDelay invokes a function N times until it returns valid output, | ||||
| // with a pause between each call. Returning either the caught error or nil. | ||||
| // When first argument is less than `1`, the function runs until a successful | ||||
| // response is returned. | ||||
| // Play: https://go.dev/play/p/tVs6CygC7m1 | ||||
| func AttemptWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) error) (int, time.Duration, error) { | ||||
| 	var err error | ||||
|  | ||||
| 	start := time.Now() | ||||
|  | ||||
| 	for i := 0; maxIteration <= 0 || i < maxIteration; i++ { | ||||
| 		err = f(i, time.Since(start)) | ||||
| 		if err == nil { | ||||
| 			return i + 1, time.Since(start), nil | ||||
| 		} | ||||
|  | ||||
| 		if maxIteration <= 0 || i+1 < maxIteration { | ||||
| 			time.Sleep(delay) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return maxIteration, time.Since(start), err | ||||
| } | ||||
|  | ||||
| // throttle ? | ||||
| // debounce ? | ||||
|   | ||||
							
								
								
									
										317
									
								
								vendor/github.com/samber/lo/slice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										317
									
								
								vendor/github.com/samber/lo/slice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,9 +2,12 @@ package lo | ||||
|  | ||||
| import ( | ||||
| 	"math/rand" | ||||
|  | ||||
| 	"golang.org/x/exp/constraints" | ||||
| ) | ||||
|  | ||||
| // Filter iterates over elements of collection, returning an array of all elements predicate returns truthy for. | ||||
| // Play: https://go.dev/play/p/Apjg3WeSi7K | ||||
| func Filter[V any](collection []V, predicate func(V, int) bool) []V { | ||||
| 	result := []V{} | ||||
|  | ||||
| @@ -18,6 +21,7 @@ func Filter[V any](collection []V, predicate func(V, int) bool) []V { | ||||
| } | ||||
|  | ||||
| // Map manipulates a slice and transforms it to a slice of another type. | ||||
| // Play: https://go.dev/play/p/OkPcYAhBo0D | ||||
| func Map[T any, R any](collection []T, iteratee func(T, int) R) []R { | ||||
| 	result := make([]R, len(collection)) | ||||
|  | ||||
| @@ -28,7 +32,26 @@ func Map[T any, R any](collection []T, iteratee func(T, int) R) []R { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FilterMap returns a slice which obtained after both filtering and mapping using the given callback function. | ||||
| // The callback function should return two values: | ||||
| //   - the result of the mapping operation and | ||||
| //   - whether the result element should be included or not. | ||||
| // | ||||
| // Play: https://go.dev/play/p/-AuYXfy7opz | ||||
| func FilterMap[T any, R any](collection []T, callback func(T, int) (R, bool)) []R { | ||||
| 	result := []R{} | ||||
|  | ||||
| 	for i, item := range collection { | ||||
| 		if r, ok := callback(item, i); ok { | ||||
| 			result = append(result, r) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FlatMap manipulates a slice and transforms and flattens it to a slice of another type. | ||||
| // Play: https://go.dev/play/p/YSoYmQTA8-U | ||||
| func FlatMap[T any, R any](collection []T, iteratee func(T, int) []R) []R { | ||||
| 	result := []R{} | ||||
|  | ||||
| @@ -41,6 +64,7 @@ func FlatMap[T any, R any](collection []T, iteratee func(T, int) []R) []R { | ||||
|  | ||||
| // Reduce reduces collection to a value which is the accumulated result of running each element in collection | ||||
| // through accumulator, where each successive invocation is supplied the return value of the previous. | ||||
| // Play: https://go.dev/play/p/R4UHXZNaaUG | ||||
| func Reduce[T any, R any](collection []T, accumulator func(R, T, int) R, initial R) R { | ||||
| 	for i, item := range collection { | ||||
| 		initial = accumulator(initial, item, i) | ||||
| @@ -49,7 +73,18 @@ func Reduce[T any, R any](collection []T, accumulator func(R, T, int) R, initial | ||||
| 	return initial | ||||
| } | ||||
|  | ||||
| // ReduceRight helper is like Reduce except that it iterates over elements of collection from right to left. | ||||
| // Play: https://go.dev/play/p/Fq3W70l7wXF | ||||
| func ReduceRight[T any, R any](collection []T, accumulator func(R, T, int) R, initial R) R { | ||||
| 	for i := len(collection) - 1; i >= 0; i-- { | ||||
| 		initial = accumulator(initial, collection[i], i) | ||||
| 	} | ||||
|  | ||||
| 	return initial | ||||
| } | ||||
|  | ||||
| // ForEach iterates over elements of collection and invokes iteratee for each element. | ||||
| // Play: https://go.dev/play/p/oofyiUPRf8t | ||||
| func ForEach[T any](collection []T, iteratee func(T, int)) { | ||||
| 	for i, item := range collection { | ||||
| 		iteratee(item, i) | ||||
| @@ -58,6 +93,7 @@ func ForEach[T any](collection []T, iteratee func(T, int)) { | ||||
|  | ||||
| // Times invokes the iteratee n times, returning an array of the results of each invocation. | ||||
| // The iteratee is invoked with index as argument. | ||||
| // Play: https://go.dev/play/p/vgQj3Glr6lT | ||||
| func Times[T any](count int, iteratee func(int) T) []T { | ||||
| 	result := make([]T, count) | ||||
|  | ||||
| @@ -70,6 +106,7 @@ func Times[T any](count int, iteratee func(int) T) []T { | ||||
|  | ||||
| // Uniq returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. | ||||
| // The order of result values is determined by the order they occur in the array. | ||||
| // Play: https://go.dev/play/p/DTzbeXZ6iEN | ||||
| func Uniq[T comparable](collection []T) []T { | ||||
| 	result := make([]T, 0, len(collection)) | ||||
| 	seen := make(map[T]struct{}, len(collection)) | ||||
| @@ -86,9 +123,10 @@ func Uniq[T comparable](collection []T) []T { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Uniq returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. | ||||
| // UniqBy returns a duplicate-free version of an array, in which only the first occurrence of each element is kept. | ||||
| // The order of result values is determined by the order they occur in the array. It accepts `iteratee` which is | ||||
| // invoked for each element in array to generate the criterion by which uniqueness is computed. | ||||
| // Play: https://go.dev/play/p/g42Z3QSb53u | ||||
| func UniqBy[T any, U comparable](collection []T, iteratee func(T) U) []T { | ||||
| 	result := make([]T, 0, len(collection)) | ||||
| 	seen := make(map[U]struct{}, len(collection)) | ||||
| @@ -108,16 +146,13 @@ func UniqBy[T any, U comparable](collection []T, iteratee func(T) U) []T { | ||||
| } | ||||
|  | ||||
| // GroupBy returns an object composed of keys generated from the results of running each element of collection through iteratee. | ||||
| // Play: https://go.dev/play/p/XnQBd_v6brd | ||||
| func GroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T { | ||||
| 	result := map[U][]T{} | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		key := iteratee(item) | ||||
|  | ||||
| 		if _, ok := result[key]; !ok { | ||||
| 			result[key] = []T{} | ||||
| 		} | ||||
|  | ||||
| 		result[key] = append(result[key], item) | ||||
| 	} | ||||
|  | ||||
| @@ -126,22 +161,25 @@ func GroupBy[T any, U comparable](collection []T, iteratee func(T) U) map[U][]T | ||||
|  | ||||
| // Chunk returns an array of elements split into groups the length of size. If array can't be split evenly, | ||||
| // the final chunk will be the remaining elements. | ||||
| // Play: https://go.dev/play/p/EeKl0AuTehH | ||||
| func Chunk[T any](collection []T, size int) [][]T { | ||||
| 	if size <= 0 { | ||||
| 		panic("Second parameter must be greater than 0") | ||||
| 	} | ||||
|  | ||||
| 	result := make([][]T, 0, len(collection)/2+1) | ||||
| 	length := len(collection) | ||||
| 	chunksNum := len(collection) / size | ||||
| 	if len(collection)%size != 0 { | ||||
| 		chunksNum += 1 | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < length; i++ { | ||||
| 		chunk := i / size | ||||
| 	result := make([][]T, 0, chunksNum) | ||||
|  | ||||
| 		if i%size == 0 { | ||||
| 			result = append(result, make([]T, 0, size)) | ||||
| 	for i := 0; i < chunksNum; i++ { | ||||
| 		last := (i + 1) * size | ||||
| 		if last > len(collection) { | ||||
| 			last = len(collection) | ||||
| 		} | ||||
|  | ||||
| 		result[chunk] = append(result[chunk], collection[i]) | ||||
| 		result = append(result, collection[i*size:last]) | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| @@ -150,6 +188,7 @@ func Chunk[T any](collection []T, size int) [][]T { | ||||
| // PartitionBy returns an array of elements split into groups. The order of grouped values is | ||||
| // determined by the order they occur in collection. The grouping is generated from the results | ||||
| // of running each element of collection through iteratee. | ||||
| // Play: https://go.dev/play/p/NfQ_nGjkgXW | ||||
| func PartitionBy[T any, K comparable](collection []T, iteratee func(x T) K) [][]T { | ||||
| 	result := [][]T{} | ||||
| 	seen := map[K]int{} | ||||
| @@ -174,18 +213,24 @@ func PartitionBy[T any, K comparable](collection []T, iteratee func(x T) K) [][] | ||||
| 	// return Values[K, []T](groups) | ||||
| } | ||||
|  | ||||
| // Flattens returns an array a single level deep. | ||||
| // Flatten returns an array a single level deep. | ||||
| // Play: https://go.dev/play/p/rbp9ORaMpjw | ||||
| func Flatten[T any](collection [][]T) []T { | ||||
| 	result := []T{} | ||||
| 	totalLen := 0 | ||||
| 	for i := range collection { | ||||
| 		totalLen += len(collection[i]) | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		result = append(result, item...) | ||||
| 	result := make([]T, 0, totalLen) | ||||
| 	for i := range collection { | ||||
| 		result = append(result, collection[i]...) | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm. | ||||
| // Play: https://go.dev/play/p/Qp73bnTDnc7 | ||||
| func Shuffle[T any](collection []T) []T { | ||||
| 	rand.Shuffle(len(collection), func(i, j int) { | ||||
| 		collection[i], collection[j] = collection[j], collection[i] | ||||
| @@ -195,6 +240,7 @@ func Shuffle[T any](collection []T) []T { | ||||
| } | ||||
|  | ||||
| // Reverse reverses array so that the first element becomes the last, the second element becomes the second to last, and so on. | ||||
| // Play: https://go.dev/play/p/fhUMLvZ7vS6 | ||||
| func Reverse[T any](collection []T) []T { | ||||
| 	length := len(collection) | ||||
| 	half := length / 2 | ||||
| @@ -208,10 +254,11 @@ func Reverse[T any](collection []T) []T { | ||||
| } | ||||
|  | ||||
| // Fill fills elements of array with `initial` value. | ||||
| // Play: https://go.dev/play/p/VwR34GzqEub | ||||
| func Fill[T Clonable[T]](collection []T, initial T) []T { | ||||
| 	result := make([]T, 0, len(collection)) | ||||
|  | ||||
| 	for _ = range collection { | ||||
| 	for range collection { | ||||
| 		result = append(result, initial.Clone()) | ||||
| 	} | ||||
|  | ||||
| @@ -219,6 +266,7 @@ func Fill[T Clonable[T]](collection []T, initial T) []T { | ||||
| } | ||||
|  | ||||
| // Repeat builds a slice with N copies of initial value. | ||||
| // Play: https://go.dev/play/p/g3uHXbmc3b6 | ||||
| func Repeat[T Clonable[T]](count int, initial T) []T { | ||||
| 	result := make([]T, 0, count) | ||||
|  | ||||
| @@ -229,7 +277,20 @@ func Repeat[T Clonable[T]](count int, initial T) []T { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // RepeatBy builds a slice with values returned by N calls of callback. | ||||
| // Play: https://go.dev/play/p/ozZLCtX_hNU | ||||
| func RepeatBy[T any](count int, predicate func(int) T) []T { | ||||
| 	result := make([]T, 0, count) | ||||
|  | ||||
| 	for i := 0; i < count; i++ { | ||||
| 		result = append(result, predicate(i)) | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // KeyBy transforms a slice or an array of structs to a map based on a pivot callback. | ||||
| // Play: https://go.dev/play/p/mdaClUAT-zZ | ||||
| func KeyBy[K comparable, V any](collection []V, iteratee func(V) K) map[K]V { | ||||
| 	result := make(map[K]V, len(collection)) | ||||
|  | ||||
| @@ -240,3 +301,223 @@ func KeyBy[K comparable, V any](collection []V, iteratee func(V) K) map[K]V { | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Associate returns a map containing key-value pairs provided by transform function applied to elements of the given slice. | ||||
| // If any of two pairs would have the same key the last one gets added to the map. | ||||
| // The order of keys in returned map is not specified and is not guaranteed to be the same from the original array. | ||||
| // Play: https://go.dev/play/p/WHa2CfMO3Lr | ||||
| func Associate[T any, K comparable, V any](collection []T, transform func(T) (K, V)) map[K]V { | ||||
| 	result := make(map[K]V) | ||||
|  | ||||
| 	for _, t := range collection { | ||||
| 		k, v := transform(t) | ||||
| 		result[k] = v | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // SliceToMap returns a map containing key-value pairs provided by transform function applied to elements of the given slice. | ||||
| // If any of two pairs would have the same key the last one gets added to the map. | ||||
| // The order of keys in returned map is not specified and is not guaranteed to be the same from the original array. | ||||
| // Alias of Associate(). | ||||
| // Play: https://go.dev/play/p/WHa2CfMO3Lr | ||||
| func SliceToMap[T any, K comparable, V any](collection []T, transform func(T) (K, V)) map[K]V { | ||||
| 	return Associate(collection, transform) | ||||
| } | ||||
|  | ||||
| // Drop drops n elements from the beginning of a slice or array. | ||||
| // Play: https://go.dev/play/p/JswS7vXRJP2 | ||||
| func Drop[T any](collection []T, n int) []T { | ||||
| 	if len(collection) <= n { | ||||
| 		return make([]T, 0) | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-n) | ||||
|  | ||||
| 	return append(result, collection[n:]...) | ||||
| } | ||||
|  | ||||
| // DropRight drops n elements from the end of a slice or array. | ||||
| // Play: https://go.dev/play/p/GG0nXkSJJa3 | ||||
| func DropRight[T any](collection []T, n int) []T { | ||||
| 	if len(collection) <= n { | ||||
| 		return []T{} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-n) | ||||
| 	return append(result, collection[:len(collection)-n]...) | ||||
| } | ||||
|  | ||||
| // DropWhile drops elements from the beginning of a slice or array while the predicate returns true. | ||||
| // Play: https://go.dev/play/p/7gBPYw2IK16 | ||||
| func DropWhile[T any](collection []T, predicate func(T) bool) []T { | ||||
| 	i := 0 | ||||
| 	for ; i < len(collection); i++ { | ||||
| 		if !predicate(collection[i]) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, len(collection)-i) | ||||
| 	return append(result, collection[i:]...) | ||||
| } | ||||
|  | ||||
| // DropRightWhile drops elements from the end of a slice or array while the predicate returns true. | ||||
| // Play: https://go.dev/play/p/3-n71oEC0Hz | ||||
| func DropRightWhile[T any](collection []T, predicate func(T) bool) []T { | ||||
| 	i := len(collection) - 1 | ||||
| 	for ; i >= 0; i-- { | ||||
| 		if !predicate(collection[i]) { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	result := make([]T, 0, i+1) | ||||
| 	return append(result, collection[:i+1]...) | ||||
| } | ||||
|  | ||||
| // Reject is the opposite of Filter, this method returns the elements of collection that predicate does not return truthy for. | ||||
| // Play: https://go.dev/play/p/YkLMODy1WEL | ||||
| func Reject[V any](collection []V, predicate func(V, int) bool) []V { | ||||
| 	result := []V{} | ||||
|  | ||||
| 	for i, item := range collection { | ||||
| 		if !predicate(item, i) { | ||||
| 			result = append(result, item) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // Count counts the number of elements in the collection that compare equal to value. | ||||
| // Play: https://go.dev/play/p/Y3FlK54yveC | ||||
| func Count[T comparable](collection []T, value T) (count int) { | ||||
| 	for _, item := range collection { | ||||
| 		if item == value { | ||||
| 			count++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return count | ||||
| } | ||||
|  | ||||
| // CountBy counts the number of elements in the collection for which predicate is true. | ||||
| // Play: https://go.dev/play/p/ByQbNYQQi4X | ||||
| func CountBy[T any](collection []T, predicate func(T) bool) (count int) { | ||||
| 	for _, item := range collection { | ||||
| 		if predicate(item) { | ||||
| 			count++ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return count | ||||
| } | ||||
|  | ||||
| // Subset returns a copy of a slice from `offset` up to `length` elements. Like `slice[start:start+length]`, but does not panic on overflow. | ||||
| // Play: https://go.dev/play/p/tOQu1GhFcog | ||||
| func Subset[T any](collection []T, offset int, length uint) []T { | ||||
| 	size := len(collection) | ||||
|  | ||||
| 	if offset < 0 { | ||||
| 		offset = size + offset | ||||
| 		if offset < 0 { | ||||
| 			offset = 0 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if offset > size { | ||||
| 		return []T{} | ||||
| 	} | ||||
|  | ||||
| 	if length > uint(size)-uint(offset) { | ||||
| 		length = uint(size - offset) | ||||
| 	} | ||||
|  | ||||
| 	return collection[offset : offset+int(length)] | ||||
| } | ||||
|  | ||||
| // Slice returns a copy of a slice from `start` up to, but not including `end`. Like `slice[start:end]`, but does not panic on overflow. | ||||
| // Play: https://go.dev/play/p/8XWYhfMMA1h | ||||
| func Slice[T any](collection []T, start int, end int) []T { | ||||
| 	size := len(collection) | ||||
|  | ||||
| 	if start >= end { | ||||
| 		return []T{} | ||||
| 	} | ||||
|  | ||||
| 	if start > size { | ||||
| 		start = size | ||||
| 	} | ||||
|  | ||||
| 	if end > size { | ||||
| 		end = size | ||||
| 	} | ||||
|  | ||||
| 	return collection[start:end] | ||||
| } | ||||
|  | ||||
| // Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new. | ||||
| // Play: https://go.dev/play/p/XfPzmf9gql6 | ||||
| func Replace[T comparable](collection []T, old T, new T, n int) []T { | ||||
| 	result := make([]T, len(collection)) | ||||
| 	copy(result, collection) | ||||
|  | ||||
| 	for i := range result { | ||||
| 		if result[i] == old && n != 0 { | ||||
| 			result[i] = new | ||||
| 			n-- | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // ReplaceAll returns a copy of the slice with all non-overlapping instances of old replaced by new. | ||||
| // Play: https://go.dev/play/p/a9xZFUHfYcV | ||||
| func ReplaceAll[T comparable](collection []T, old T, new T) []T { | ||||
| 	return Replace(collection, old, new, -1) | ||||
| } | ||||
|  | ||||
| // Compact returns a slice of all non-zero elements. | ||||
| // Play: https://go.dev/play/p/tXiy-iK6PAc | ||||
| func Compact[T comparable](collection []T) []T { | ||||
| 	var zero T | ||||
|  | ||||
| 	result := []T{} | ||||
|  | ||||
| 	for _, item := range collection { | ||||
| 		if item != zero { | ||||
| 			result = append(result, item) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // IsSorted checks if a slice is sorted. | ||||
| // Play: https://go.dev/play/p/mc3qR-t4mcx | ||||
| func IsSorted[T constraints.Ordered](collection []T) bool { | ||||
| 	for i := 1; i < len(collection); i++ { | ||||
| 		if collection[i-1] > collection[i] { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // IsSortedByKey checks if a slice is sorted by iteratee. | ||||
| // Play: https://go.dev/play/p/wiG6XyBBu49 | ||||
| func IsSortedByKey[T any, K constraints.Ordered](collection []T, iteratee func(T) K) bool { | ||||
| 	size := len(collection) | ||||
|  | ||||
| 	for i := 0; i < size-1; i++ { | ||||
| 		if iteratee(collection[i]) > iteratee(collection[i+1]) { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|   | ||||
							
								
								
									
										65
									
								
								vendor/github.com/samber/lo/string.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/samber/lo/string.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| package lo | ||||
|  | ||||
| import ( | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| // Substring return part of a string. | ||||
| // Play: https://go.dev/play/p/TQlxQi82Lu1 | ||||
| func Substring[T ~string](str T, offset int, length uint) T { | ||||
| 	size := len(str) | ||||
|  | ||||
| 	if offset < 0 { | ||||
| 		offset = size + offset | ||||
| 		if offset < 0 { | ||||
| 			offset = 0 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if offset > size { | ||||
| 		return Empty[T]() | ||||
| 	} | ||||
|  | ||||
| 	if length > uint(size)-uint(offset) { | ||||
| 		length = uint(size - offset) | ||||
| 	} | ||||
|  | ||||
| 	return str[offset : offset+int(length)] | ||||
| } | ||||
|  | ||||
| // ChunkString returns an array of strings split into groups the length of size. If array can't be split evenly, | ||||
| // the final chunk will be the remaining elements. | ||||
| // Play: https://go.dev/play/p/__FLTuJVz54 | ||||
| func ChunkString[T ~string](str T, size int) []T { | ||||
| 	if size <= 0 { | ||||
| 		panic("lo.ChunkString: Size parameter must be greater than 0") | ||||
| 	} | ||||
|  | ||||
| 	if len(str) == 0 { | ||||
| 		return []T{""} | ||||
| 	} | ||||
|  | ||||
| 	if size >= len(str) { | ||||
| 		return []T{str} | ||||
| 	} | ||||
|  | ||||
| 	var chunks []T = make([]T, 0, ((len(str)-1)/size)+1) | ||||
| 	currentLen := 0 | ||||
| 	currentStart := 0 | ||||
| 	for i := range str { | ||||
| 		if currentLen == size { | ||||
| 			chunks = append(chunks, str[currentStart:i]) | ||||
| 			currentLen = 0 | ||||
| 			currentStart = i | ||||
| 		} | ||||
| 		currentLen++ | ||||
| 	} | ||||
| 	chunks = append(chunks, str[currentStart:]) | ||||
| 	return chunks | ||||
| } | ||||
|  | ||||
| // RuneLength is an alias to utf8.RuneCountInString which returns the number of runes in string. | ||||
| // Play: https://go.dev/play/p/tuhgW_lWY8l | ||||
| func RuneLength(str string) int { | ||||
| 	return utf8.RuneCountInString(str) | ||||
| } | ||||
							
								
								
									
										32
									
								
								vendor/github.com/samber/lo/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/samber/lo/test.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| package lo | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // https://github.com/stretchr/testify/issues/1101 | ||||
| func testWithTimeout(t *testing.T, timeout time.Duration) { | ||||
| 	t.Helper() | ||||
|  | ||||
| 	testFinished := make(chan struct{}) | ||||
| 	t.Cleanup(func() { close(testFinished) }) | ||||
|  | ||||
| 	go func() { | ||||
| 		select { | ||||
| 		case <-testFinished: | ||||
| 		case <-time.After(timeout): | ||||
| 			t.Errorf("test timed out after %s", timeout) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
|  | ||||
| type foo struct { | ||||
| 	bar string | ||||
| } | ||||
|  | ||||
| func (f foo) Clone() foo { | ||||
| 	return foo{f.bar} | ||||
| } | ||||
							
								
								
									
										220
									
								
								vendor/github.com/samber/lo/tuples.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										220
									
								
								vendor/github.com/samber/lo/tuples.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +1,113 @@ | ||||
| package lo | ||||
|  | ||||
| func longestCollection(collections ...[]interface{}) int { | ||||
| 	max := 0 | ||||
| // T2 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T2[A any, B any](a A, b B) Tuple2[A, B] { | ||||
| 	return Tuple2[A, B]{A: a, B: b} | ||||
| } | ||||
|  | ||||
| 	for _, collection := range collections { | ||||
| 		if len(collection) > max { | ||||
| 			max = len(collection) | ||||
| 		} | ||||
| 	} | ||||
| // T3 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T3[A any, B any, C any](a A, b B, c C) Tuple3[A, B, C] { | ||||
| 	return Tuple3[A, B, C]{A: a, B: b, C: c} | ||||
| } | ||||
|  | ||||
| 	return max | ||||
| // T4 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T4[A any, B any, C any, D any](a A, b B, c C, d D) Tuple4[A, B, C, D] { | ||||
| 	return Tuple4[A, B, C, D]{A: a, B: b, C: c, D: d} | ||||
| } | ||||
|  | ||||
| // T5 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T5[A any, B any, C any, D any, E any](a A, b B, c C, d D, e E) Tuple5[A, B, C, D, E] { | ||||
| 	return Tuple5[A, B, C, D, E]{A: a, B: b, C: c, D: d, E: e} | ||||
| } | ||||
|  | ||||
| // T6 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T6[A any, B any, C any, D any, E any, F any](a A, b B, c C, d D, e E, f F) Tuple6[A, B, C, D, E, F] { | ||||
| 	return Tuple6[A, B, C, D, E, F]{A: a, B: b, C: c, D: d, E: e, F: f} | ||||
| } | ||||
|  | ||||
| // T7 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T7[A any, B any, C any, D any, E any, F any, G any](a A, b B, c C, d D, e E, f F, g G) Tuple7[A, B, C, D, E, F, G] { | ||||
| 	return Tuple7[A, B, C, D, E, F, G]{A: a, B: b, C: c, D: d, E: e, F: f, G: g} | ||||
| } | ||||
|  | ||||
| // T8 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T8[A any, B any, C any, D any, E any, F any, G any, H any](a A, b B, c C, d D, e E, f F, g G, h H) Tuple8[A, B, C, D, E, F, G, H] { | ||||
| 	return Tuple8[A, B, C, D, E, F, G, H]{A: a, B: b, C: c, D: d, E: e, F: f, G: g, H: h} | ||||
| } | ||||
|  | ||||
| // T8 creates a tuple from a list of values. | ||||
| // Play: https://go.dev/play/p/IllL3ZO4BQm | ||||
| func T9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a A, b B, c C, d D, e E, f F, g G, h H, i I) Tuple9[A, B, C, D, E, F, G, H, I] { | ||||
| 	return Tuple9[A, B, C, D, E, F, G, H, I]{A: a, B: b, C: c, D: d, E: e, F: f, G: g, H: h, I: i} | ||||
| } | ||||
|  | ||||
| // Unpack2 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack2[A any, B any](tuple Tuple2[A, B]) (A, B) { | ||||
| 	return tuple.A, tuple.B | ||||
| } | ||||
|  | ||||
| // Unpack3 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack3[A any, B any, C any](tuple Tuple3[A, B, C]) (A, B, C) { | ||||
| 	return tuple.A, tuple.B, tuple.C | ||||
| } | ||||
|  | ||||
| // Unpack4 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack4[A any, B any, C any, D any](tuple Tuple4[A, B, C, D]) (A, B, C, D) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D | ||||
| } | ||||
|  | ||||
| // Unpack5 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack5[A any, B any, C any, D any, E any](tuple Tuple5[A, B, C, D, E]) (A, B, C, D, E) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D, tuple.E | ||||
| } | ||||
|  | ||||
| // Unpack6 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack6[A any, B any, C any, D any, E any, F any](tuple Tuple6[A, B, C, D, E, F]) (A, B, C, D, E, F) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D, tuple.E, tuple.F | ||||
| } | ||||
|  | ||||
| // Unpack7 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack7[A any, B any, C any, D any, E any, F any, G any](tuple Tuple7[A, B, C, D, E, F, G]) (A, B, C, D, E, F, G) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D, tuple.E, tuple.F, tuple.G | ||||
| } | ||||
|  | ||||
| // Unpack8 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack8[A any, B any, C any, D any, E any, F any, G any, H any](tuple Tuple8[A, B, C, D, E, F, G, H]) (A, B, C, D, E, F, G, H) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D, tuple.E, tuple.F, tuple.G, tuple.H | ||||
| } | ||||
|  | ||||
| // Unpack9 returns values contained in tuple. | ||||
| // Play: https://go.dev/play/p/xVP_k0kJ96W | ||||
| func Unpack9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuple Tuple9[A, B, C, D, E, F, G, H, I]) (A, B, C, D, E, F, G, H, I) { | ||||
| 	return tuple.A, tuple.B, tuple.C, tuple.D, tuple.E, tuple.F, tuple.G, tuple.H, tuple.I | ||||
| } | ||||
|  | ||||
| // Zip2 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B] { | ||||
| 	size := Max[int]([]int{len(a), len(b)}) | ||||
| 	size := Max([]int{len(a), len(b)}) | ||||
|  | ||||
| 	result := make([]Tuple2[A, B], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
|  | ||||
| 		result = append(result, Tuple2[A, B]{ | ||||
| 			A: _a, | ||||
| @@ -36,15 +121,16 @@ func Zip2[A any, B any](a []A, b []B) []Tuple2[A, B] { | ||||
| // Zip3 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c)}) | ||||
|  | ||||
| 	result := make([]Tuple3[A, B, C], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
|  | ||||
| 		result = append(result, Tuple3[A, B, C]{ | ||||
| 			A: _a, | ||||
| @@ -59,16 +145,17 @@ func Zip3[A any, B any, C any](a []A, b []B, c []C) []Tuple3[A, B, C] { | ||||
| // Zip4 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, C, D] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d)}) | ||||
|  | ||||
| 	result := make([]Tuple4[A, B, C, D], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
|  | ||||
| 		result = append(result, Tuple4[A, B, C, D]{ | ||||
| 			A: _a, | ||||
| @@ -84,17 +171,18 @@ func Zip4[A any, B any, C any, D any](a []A, b []B, c []C, d []D) []Tuple4[A, B, | ||||
| // Zip5 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) []Tuple5[A, B, C, D, E] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d), len(e)}) | ||||
|  | ||||
| 	result := make([]Tuple5[A, B, C, D, E], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_e, _ := Nth[E](e, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
| 		_e, _ := Nth(e, index) | ||||
|  | ||||
| 		result = append(result, Tuple5[A, B, C, D, E]{ | ||||
| 			A: _a, | ||||
| @@ -111,18 +199,19 @@ func Zip5[A any, B any, C any, D any, E any](a []A, b []B, c []C, d []D, e []E) | ||||
| // Zip6 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, e []E, f []F) []Tuple6[A, B, C, D, E, F] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) | ||||
|  | ||||
| 	result := make([]Tuple6[A, B, C, D, E, F], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_e, _ := Nth[E](e, index) | ||||
| 		_f, _ := Nth[F](f, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
| 		_e, _ := Nth(e, index) | ||||
| 		_f, _ := Nth(f, index) | ||||
|  | ||||
| 		result = append(result, Tuple6[A, B, C, D, E, F]{ | ||||
| 			A: _a, | ||||
| @@ -140,19 +229,20 @@ func Zip6[A any, B any, C any, D any, E any, F any](a []A, b []B, c []C, d []D, | ||||
| // Zip7 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, d []D, e []E, f []F, g []G) []Tuple7[A, B, C, D, E, F, G] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)}) | ||||
|  | ||||
| 	result := make([]Tuple7[A, B, C, D, E, F, G], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_e, _ := Nth[E](e, index) | ||||
| 		_f, _ := Nth[F](f, index) | ||||
| 		_g, _ := Nth[G](g, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
| 		_e, _ := Nth(e, index) | ||||
| 		_f, _ := Nth(f, index) | ||||
| 		_g, _ := Nth(g, index) | ||||
|  | ||||
| 		result = append(result, Tuple7[A, B, C, D, E, F, G]{ | ||||
| 			A: _a, | ||||
| @@ -171,20 +261,21 @@ func Zip7[A any, B any, C any, D any, E any, F any, G any](a []A, b []B, c []C, | ||||
| // Zip8 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H) []Tuple8[A, B, C, D, E, F, G, H] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h)}) | ||||
|  | ||||
| 	result := make([]Tuple8[A, B, C, D, E, F, G, H], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_e, _ := Nth[E](e, index) | ||||
| 		_f, _ := Nth[F](f, index) | ||||
| 		_g, _ := Nth[G](g, index) | ||||
| 		_h, _ := Nth[H](h, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
| 		_e, _ := Nth(e, index) | ||||
| 		_f, _ := Nth(f, index) | ||||
| 		_g, _ := Nth(g, index) | ||||
| 		_h, _ := Nth(h, index) | ||||
|  | ||||
| 		result = append(result, Tuple8[A, B, C, D, E, F, G, H]{ | ||||
| 			A: _a, | ||||
| @@ -204,21 +295,22 @@ func Zip8[A any, B any, C any, D any, E any, F any, G any, H any](a []A, b []B, | ||||
| // Zip9 creates a slice of grouped elements, the first of which contains the first elements | ||||
| // of the given arrays, the second of which contains the second elements of the given arrays, and so on. | ||||
| // When collections have different size, the Tuple attributes are filled with zero value. | ||||
| // Play: https://go.dev/play/p/jujaA6GaJTp | ||||
| func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I) []Tuple9[A, B, C, D, E, F, G, H, I] { | ||||
| 	size := Max[int]([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)}) | ||||
| 	size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)}) | ||||
|  | ||||
| 	result := make([]Tuple9[A, B, C, D, E, F, G, H, I], 0, size) | ||||
|  | ||||
| 	for index := 0; index < size; index++ { | ||||
| 		_a, _ := Nth[A](a, index) | ||||
| 		_b, _ := Nth[B](b, index) | ||||
| 		_c, _ := Nth[C](c, index) | ||||
| 		_d, _ := Nth[D](d, index) | ||||
| 		_e, _ := Nth[E](e, index) | ||||
| 		_f, _ := Nth[F](f, index) | ||||
| 		_g, _ := Nth[G](g, index) | ||||
| 		_h, _ := Nth[H](h, index) | ||||
| 		_i, _ := Nth[I](i, index) | ||||
| 		_a, _ := Nth(a, index) | ||||
| 		_b, _ := Nth(b, index) | ||||
| 		_c, _ := Nth(c, index) | ||||
| 		_d, _ := Nth(d, index) | ||||
| 		_e, _ := Nth(e, index) | ||||
| 		_f, _ := Nth(f, index) | ||||
| 		_g, _ := Nth(g, index) | ||||
| 		_h, _ := Nth(h, index) | ||||
| 		_i, _ := Nth(i, index) | ||||
|  | ||||
| 		result = append(result, Tuple9[A, B, C, D, E, F, G, H, I]{ | ||||
| 			A: _a, | ||||
| @@ -238,6 +330,7 @@ func Zip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](a []A, | ||||
|  | ||||
| // Unzip2 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -253,6 +346,7 @@ func Unzip2[A any, B any](tuples []Tuple2[A, B]) ([]A, []B) { | ||||
|  | ||||
| // Unzip3 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -270,6 +364,7 @@ func Unzip3[A any, B any, C any](tuples []Tuple3[A, B, C]) ([]A, []B, []C) { | ||||
|  | ||||
| // Unzip4 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, []C, []D) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -289,6 +384,7 @@ func Unzip4[A any, B any, C any, D any](tuples []Tuple4[A, B, C, D]) ([]A, []B, | ||||
|  | ||||
| // Unzip5 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ([]A, []B, []C, []D, []E) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -310,6 +406,7 @@ func Unzip5[A any, B any, C any, D any, E any](tuples []Tuple5[A, B, C, D, E]) ( | ||||
|  | ||||
| // Unzip6 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D, E, F]) ([]A, []B, []C, []D, []E, []F) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -333,6 +430,7 @@ func Unzip6[A any, B any, C any, D any, E any, F any](tuples []Tuple6[A, B, C, D | ||||
|  | ||||
| // Unzip7 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, B, C, D, E, F, G]) ([]A, []B, []C, []D, []E, []F, []G) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -358,6 +456,7 @@ func Unzip7[A any, B any, C any, D any, E any, F any, G any](tuples []Tuple7[A, | ||||
|  | ||||
| // Unzip8 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tuple8[A, B, C, D, E, F, G, H]) ([]A, []B, []C, []D, []E, []F, []G, []H) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
| @@ -385,6 +484,7 @@ func Unzip8[A any, B any, C any, D any, E any, F any, G any, H any](tuples []Tup | ||||
|  | ||||
| // Unzip9 accepts an array of grouped elements and creates an array regrouping the elements | ||||
| // to their pre-zip configuration. | ||||
| // Play: https://go.dev/play/p/ciHugugvaAW | ||||
| func Unzip9[A any, B any, C any, D any, E any, F any, G any, H any, I any](tuples []Tuple9[A, B, C, D, E, F, G, H, I]) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) { | ||||
| 	size := len(tuples) | ||||
| 	r1 := make([]A, 0, size) | ||||
|   | ||||
							
								
								
									
										88
									
								
								vendor/github.com/samber/lo/type_manipulation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								vendor/github.com/samber/lo/type_manipulation.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| package lo | ||||
|  | ||||
| // ToPtr returns a pointer copy of value. | ||||
| func ToPtr[T any](x T) *T { | ||||
| 	return &x | ||||
| } | ||||
|  | ||||
| // FromPtr returns the pointer value or empty. | ||||
| func FromPtr[T any](x *T) T { | ||||
| 	if x == nil { | ||||
| 		return Empty[T]() | ||||
| 	} | ||||
|  | ||||
| 	return *x | ||||
| } | ||||
|  | ||||
| // FromPtrOr returns the pointer value or the fallback value. | ||||
| func FromPtrOr[T any](x *T, fallback T) T { | ||||
| 	if x == nil { | ||||
| 		return fallback | ||||
| 	} | ||||
|  | ||||
| 	return *x | ||||
| } | ||||
|  | ||||
| // ToSlicePtr returns a slice of pointer copy of value. | ||||
| func ToSlicePtr[T any](collection []T) []*T { | ||||
| 	return Map(collection, func(x T, _ int) *T { | ||||
| 		return &x | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| // ToAnySlice returns a slice with all elements mapped to `any` type | ||||
| func ToAnySlice[T any](collection []T) []any { | ||||
| 	result := make([]any, len(collection)) | ||||
| 	for i, item := range collection { | ||||
| 		result[i] = item | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FromAnySlice returns an `any` slice with all elements mapped to a type. | ||||
| // Returns false in case of type conversion failure. | ||||
| func FromAnySlice[T any](in []any) (out []T, ok bool) { | ||||
| 	defer func() { | ||||
| 		if r := recover(); r != nil { | ||||
| 			out = []T{} | ||||
| 			ok = false | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	result := make([]T, len(in)) | ||||
| 	for i, item := range in { | ||||
| 		result[i] = item.(T) | ||||
| 	} | ||||
| 	return result, true | ||||
| } | ||||
|  | ||||
| // Empty returns an empty value. | ||||
| func Empty[T any]() T { | ||||
| 	var zero T | ||||
| 	return zero | ||||
| } | ||||
|  | ||||
| // IsEmpty returns true if argument is a zero value. | ||||
| func IsEmpty[T comparable](v T) bool { | ||||
| 	var zero T | ||||
| 	return zero == v | ||||
| } | ||||
|  | ||||
| // IsNotEmpty returns true if argument is not a zero value. | ||||
| func IsNotEmpty[T comparable](v T) bool { | ||||
| 	var zero T | ||||
| 	return zero != v | ||||
| } | ||||
|  | ||||
| // Coalesce returns the first non-empty arguments. Arguments must be comparable. | ||||
| func Coalesce[T comparable](v ...T) (result T, ok bool) { | ||||
| 	for _, e := range v { | ||||
| 		if e != result { | ||||
| 			result = e | ||||
| 			ok = true | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										76
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +1,10 @@ | ||||
| package assert | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| type CompareType int | ||||
| @@ -30,6 +32,9 @@ var ( | ||||
| 	float64Type = reflect.TypeOf(float64(1)) | ||||
|  | ||||
| 	stringType = reflect.TypeOf("") | ||||
|  | ||||
| 	timeType  = reflect.TypeOf(time.Time{}) | ||||
| 	bytesType = reflect.TypeOf([]byte{}) | ||||
| ) | ||||
|  | ||||
| func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { | ||||
| @@ -299,6 +304,47 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { | ||||
| 				return compareLess, true | ||||
| 			} | ||||
| 		} | ||||
| 	// Check for known struct types we can check for compare results. | ||||
| 	case reflect.Struct: | ||||
| 		{ | ||||
| 			// All structs enter here. We're not interested in most types. | ||||
| 			if !canConvert(obj1Value, timeType) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// time.Time can compared! | ||||
| 			timeObj1, ok := obj1.(time.Time) | ||||
| 			if !ok { | ||||
| 				timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time) | ||||
| 			} | ||||
|  | ||||
| 			timeObj2, ok := obj2.(time.Time) | ||||
| 			if !ok { | ||||
| 				timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time) | ||||
| 			} | ||||
|  | ||||
| 			return compare(timeObj1.UnixNano(), timeObj2.UnixNano(), reflect.Int64) | ||||
| 		} | ||||
| 	case reflect.Slice: | ||||
| 		{ | ||||
| 			// We only care about the []byte type. | ||||
| 			if !canConvert(obj1Value, bytesType) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// []byte can be compared! | ||||
| 			bytesObj1, ok := obj1.([]byte) | ||||
| 			if !ok { | ||||
| 				bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte) | ||||
|  | ||||
| 			} | ||||
| 			bytesObj2, ok := obj2.([]byte) | ||||
| 			if !ok { | ||||
| 				bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte) | ||||
| 			} | ||||
|  | ||||
| 			return CompareType(bytes.Compare(bytesObj1, bytesObj2)), true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return compareEqual, false | ||||
| @@ -310,7 +356,10 @@ func compare(obj1, obj2 interface{}, kind reflect.Kind) (CompareType, bool) { | ||||
| //    assert.Greater(t, float64(2), float64(1)) | ||||
| //    assert.Greater(t, "b", "a") | ||||
| func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // GreaterOrEqual asserts that the first element is greater than or equal to the second | ||||
| @@ -320,7 +369,10 @@ func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface | ||||
| //    assert.GreaterOrEqual(t, "b", "a") | ||||
| //    assert.GreaterOrEqual(t, "b", "b") | ||||
| func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareGreater, compareEqual}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // Less asserts that the first element is less than the second | ||||
| @@ -329,7 +381,10 @@ func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...in | ||||
| //    assert.Less(t, float64(1), float64(2)) | ||||
| //    assert.Less(t, "a", "b") | ||||
| func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // LessOrEqual asserts that the first element is less than or equal to the second | ||||
| @@ -339,7 +394,10 @@ func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) | ||||
| //    assert.LessOrEqual(t, "a", "b") | ||||
| //    assert.LessOrEqual(t, "b", "b") | ||||
| func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return compareTwoValues(t, e1, e2, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // Positive asserts that the specified element is positive | ||||
| @@ -347,8 +405,11 @@ func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inter | ||||
| //    assert.Positive(t, 1) | ||||
| //    assert.Positive(t, 1.23) | ||||
| func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	zero := reflect.Zero(reflect.TypeOf(e)) | ||||
| 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs) | ||||
| 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareGreater}, "\"%v\" is not positive", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // Negative asserts that the specified element is negative | ||||
| @@ -356,8 +417,11 @@ func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { | ||||
| //    assert.Negative(t, -1) | ||||
| //    assert.Negative(t, -1.23) | ||||
| func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	zero := reflect.Zero(reflect.TypeOf(e)) | ||||
| 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs) | ||||
| 	return compareTwoValues(t, e, zero.Interface(), []CompareType{compareLess}, "\"%v\" is not negative", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []CompareType, failMessage string, msgAndArgs ...interface{}) bool { | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare_can_convert.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| //go:build go1.17 | ||||
| // +build go1.17 | ||||
|  | ||||
| // TODO: once support for Go 1.16 is dropped, this file can be | ||||
| //       merged/removed with assertion_compare_go1.17_test.go and | ||||
| //       assertion_compare_legacy.go | ||||
|  | ||||
| package assert | ||||
|  | ||||
| import "reflect" | ||||
|  | ||||
| // Wrapper around reflect.Value.CanConvert, for compatibility | ||||
| // reasons. | ||||
| func canConvert(value reflect.Value, to reflect.Type) bool { | ||||
| 	return value.CanConvert(to) | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/stretchr/testify/assert/assertion_compare_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| //go:build !go1.17 | ||||
| // +build !go1.17 | ||||
|  | ||||
| // TODO: once support for Go 1.16 is dropped, this file can be | ||||
| //       merged/removed with assertion_compare_go1.17_test.go and | ||||
| //       assertion_compare_can_convert.go | ||||
|  | ||||
| package assert | ||||
|  | ||||
| import "reflect" | ||||
|  | ||||
| // Older versions of Go does not have the reflect.Value.CanConvert | ||||
| // method. | ||||
| func canConvert(value reflect.Value, to reflect.Type) bool { | ||||
| 	return false | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/github.com/stretchr/testify/assert/assertion_format.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/stretchr/testify/assert/assertion_format.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -123,6 +123,18 @@ func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...int | ||||
| 	return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...) | ||||
| } | ||||
|  | ||||
| // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) | ||||
| // and that the error contains the specified substring. | ||||
| // | ||||
| //   actualObj, err := SomeFunction() | ||||
| //   assert.ErrorContainsf(t, err,  expectedErrorSubString, "error message %s", "formatted") | ||||
| func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...) | ||||
| } | ||||
|  | ||||
| // ErrorIsf asserts that at least one of the errors in err's chain matches target. | ||||
| // This is a wrapper for errors.Is. | ||||
| func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool { | ||||
| @@ -724,6 +736,16 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim | ||||
| 	return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) | ||||
| } | ||||
|  | ||||
| // WithinRangef asserts that a time is within a time range (inclusive). | ||||
| // | ||||
| //   assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") | ||||
| func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...) | ||||
| } | ||||
|  | ||||
| // YAMLEqf asserts that two YAML strings are equivalent. | ||||
| func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
|   | ||||
							
								
								
									
										44
									
								
								vendor/github.com/stretchr/testify/assert/assertion_forward.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/stretchr/testify/assert/assertion_forward.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -222,6 +222,30 @@ func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args .. | ||||
| 	return ErrorAsf(a.t, err, target, msg, args...) | ||||
| } | ||||
|  | ||||
| // ErrorContains asserts that a function returned an error (i.e. not `nil`) | ||||
| // and that the error contains the specified substring. | ||||
| // | ||||
| //   actualObj, err := SomeFunction() | ||||
| //   a.ErrorContains(err,  expectedErrorSubString) | ||||
| func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := a.t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return ErrorContains(a.t, theError, contains, msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // ErrorContainsf asserts that a function returned an error (i.e. not `nil`) | ||||
| // and that the error contains the specified substring. | ||||
| // | ||||
| //   actualObj, err := SomeFunction() | ||||
| //   a.ErrorContainsf(err,  expectedErrorSubString, "error message %s", "formatted") | ||||
| func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool { | ||||
| 	if h, ok := a.t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return ErrorContainsf(a.t, theError, contains, msg, args...) | ||||
| } | ||||
|  | ||||
| // ErrorIs asserts that at least one of the errors in err's chain matches target. | ||||
| // This is a wrapper for errors.Is. | ||||
| func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool { | ||||
| @@ -1437,6 +1461,26 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta | ||||
| 	return WithinDurationf(a.t, expected, actual, delta, msg, args...) | ||||
| } | ||||
|  | ||||
| // WithinRange asserts that a time is within a time range (inclusive). | ||||
| // | ||||
| //   a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) | ||||
| func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := a.t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return WithinRange(a.t, actual, start, end, msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // WithinRangef asserts that a time is within a time range (inclusive). | ||||
| // | ||||
| //   a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") | ||||
| func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool { | ||||
| 	if h, ok := a.t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	return WithinRangef(a.t, actual, start, end, msg, args...) | ||||
| } | ||||
|  | ||||
| // YAMLEq asserts that two YAML strings are equivalent. | ||||
| func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := a.t.(tHelper); ok { | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/stretchr/testify/assert/assertion_order.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/stretchr/testify/assert/assertion_order.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -50,7 +50,7 @@ func isOrdered(t TestingT, object interface{}, allowedComparesResults []CompareT | ||||
| //    assert.IsIncreasing(t, []float{1, 2}) | ||||
| //    assert.IsIncreasing(t, []string{"a", "b"}) | ||||
| func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs) | ||||
| 	return isOrdered(t, object, []CompareType{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // IsNonIncreasing asserts that the collection is not increasing | ||||
| @@ -59,7 +59,7 @@ func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo | ||||
| //    assert.IsNonIncreasing(t, []float{2, 1}) | ||||
| //    assert.IsNonIncreasing(t, []string{"b", "a"}) | ||||
| func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs) | ||||
| 	return isOrdered(t, object, []CompareType{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // IsDecreasing asserts that the collection is decreasing | ||||
| @@ -68,7 +68,7 @@ func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) | ||||
| //    assert.IsDecreasing(t, []float{2, 1}) | ||||
| //    assert.IsDecreasing(t, []string{"b", "a"}) | ||||
| func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs) | ||||
| 	return isOrdered(t, object, []CompareType{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) | ||||
| } | ||||
|  | ||||
| // IsNonDecreasing asserts that the collection is not decreasing | ||||
| @@ -77,5 +77,5 @@ func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) boo | ||||
| //    assert.IsNonDecreasing(t, []float{1, 2}) | ||||
| //    assert.IsNonDecreasing(t, []string{"a", "b"}) | ||||
| func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { | ||||
| 	return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs) | ||||
| 	return isOrdered(t, object, []CompareType{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) | ||||
| } | ||||
|   | ||||
							
								
								
									
										190
									
								
								vendor/github.com/stretchr/testify/assert/assertions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										190
									
								
								vendor/github.com/stretchr/testify/assert/assertions.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,6 +8,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| @@ -144,7 +145,8 @@ func CallerInfo() []string { | ||||
| 		if len(parts) > 1 { | ||||
| 			dir := parts[len(parts)-2] | ||||
| 			if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { | ||||
| 				callers = append(callers, fmt.Sprintf("%s:%d", file, line)) | ||||
| 				path, _ := filepath.Abs(file) | ||||
| 				callers = append(callers, fmt.Sprintf("%s:%d", path, line)) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -563,16 +565,17 @@ func isEmpty(object interface{}) bool { | ||||
|  | ||||
| 	switch objValue.Kind() { | ||||
| 	// collection types are empty when they have no element | ||||
| 	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice: | ||||
| 	case reflect.Chan, reflect.Map, reflect.Slice: | ||||
| 		return objValue.Len() == 0 | ||||
| 		// pointers are empty if nil or if the value they point to is empty | ||||
| 	// pointers are empty if nil or if the value they point to is empty | ||||
| 	case reflect.Ptr: | ||||
| 		if objValue.IsNil() { | ||||
| 			return true | ||||
| 		} | ||||
| 		deref := objValue.Elem().Interface() | ||||
| 		return isEmpty(deref) | ||||
| 		// for all other types, compare against the zero value | ||||
| 	// for all other types, compare against the zero value | ||||
| 	// array types are empty when they match their zero-initialized state | ||||
| 	default: | ||||
| 		zero := reflect.Zero(objValue.Type()) | ||||
| 		return reflect.DeepEqual(object, zero.Interface()) | ||||
| @@ -718,10 +721,14 @@ func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...inte | ||||
| // return (false, false) if impossible. | ||||
| // return (true, false) if element was not found. | ||||
| // return (true, true) if element was found. | ||||
| func includeElement(list interface{}, element interface{}) (ok, found bool) { | ||||
| func containsElement(list interface{}, element interface{}) (ok, found bool) { | ||||
|  | ||||
| 	listValue := reflect.ValueOf(list) | ||||
| 	listKind := reflect.TypeOf(list).Kind() | ||||
| 	listType := reflect.TypeOf(list) | ||||
| 	if listType == nil { | ||||
| 		return false, false | ||||
| 	} | ||||
| 	listKind := listType.Kind() | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			ok = false | ||||
| @@ -764,7 +771,7 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo | ||||
| 		h.Helper() | ||||
| 	} | ||||
|  | ||||
| 	ok, found := includeElement(s, contains) | ||||
| 	ok, found := containsElement(s, contains) | ||||
| 	if !ok { | ||||
| 		return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...) | ||||
| 	} | ||||
| @@ -787,7 +794,7 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) | ||||
| 		h.Helper() | ||||
| 	} | ||||
|  | ||||
| 	ok, found := includeElement(s, contains) | ||||
| 	ok, found := containsElement(s, contains) | ||||
| 	if !ok { | ||||
| 		return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", s), msgAndArgs...) | ||||
| 	} | ||||
| @@ -811,7 +818,6 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok | ||||
| 		return true // we consider nil to be equal to the nil set | ||||
| 	} | ||||
|  | ||||
| 	subsetValue := reflect.ValueOf(subset) | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			ok = false | ||||
| @@ -821,17 +827,35 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok | ||||
| 	listKind := reflect.TypeOf(list).Kind() | ||||
| 	subsetKind := reflect.TypeOf(subset).Kind() | ||||
|  | ||||
| 	if listKind != reflect.Array && listKind != reflect.Slice { | ||||
| 	if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { | ||||
| 		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	if subsetKind != reflect.Array && subsetKind != reflect.Slice { | ||||
| 	if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { | ||||
| 		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	subsetValue := reflect.ValueOf(subset) | ||||
| 	if subsetKind == reflect.Map && listKind == reflect.Map { | ||||
| 		listValue := reflect.ValueOf(list) | ||||
| 		subsetKeys := subsetValue.MapKeys() | ||||
|  | ||||
| 		for i := 0; i < len(subsetKeys); i++ { | ||||
| 			subsetKey := subsetKeys[i] | ||||
| 			subsetElement := subsetValue.MapIndex(subsetKey).Interface() | ||||
| 			listElement := listValue.MapIndex(subsetKey).Interface() | ||||
|  | ||||
| 			if !ObjectsAreEqual(subsetElement, listElement) { | ||||
| 				return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, subsetElement), msgAndArgs...) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < subsetValue.Len(); i++ { | ||||
| 		element := subsetValue.Index(i).Interface() | ||||
| 		ok, found := includeElement(list, element) | ||||
| 		ok, found := containsElement(list, element) | ||||
| 		if !ok { | ||||
| 			return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) | ||||
| 		} | ||||
| @@ -852,10 +876,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	if subset == nil { | ||||
| 		return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) | ||||
| 		return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	subsetValue := reflect.ValueOf(subset) | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			ok = false | ||||
| @@ -865,17 +888,35 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) | ||||
| 	listKind := reflect.TypeOf(list).Kind() | ||||
| 	subsetKind := reflect.TypeOf(subset).Kind() | ||||
|  | ||||
| 	if listKind != reflect.Array && listKind != reflect.Slice { | ||||
| 	if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { | ||||
| 		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	if subsetKind != reflect.Array && subsetKind != reflect.Slice { | ||||
| 	if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { | ||||
| 		return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	subsetValue := reflect.ValueOf(subset) | ||||
| 	if subsetKind == reflect.Map && listKind == reflect.Map { | ||||
| 		listValue := reflect.ValueOf(list) | ||||
| 		subsetKeys := subsetValue.MapKeys() | ||||
|  | ||||
| 		for i := 0; i < len(subsetKeys); i++ { | ||||
| 			subsetKey := subsetKeys[i] | ||||
| 			subsetElement := subsetValue.MapIndex(subsetKey).Interface() | ||||
| 			listElement := listValue.MapIndex(subsetKey).Interface() | ||||
|  | ||||
| 			if !ObjectsAreEqual(subsetElement, listElement) { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < subsetValue.Len(); i++ { | ||||
| 		element := subsetValue.Index(i).Interface() | ||||
| 		ok, found := includeElement(list, element) | ||||
| 		ok, found := containsElement(list, element) | ||||
| 		if !ok { | ||||
| 			return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) | ||||
| 		} | ||||
| @@ -1000,27 +1041,21 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { | ||||
| type PanicTestFunc func() | ||||
|  | ||||
| // didPanic returns true if the function passed to it panics. Otherwise, it returns false. | ||||
| func didPanic(f PanicTestFunc) (bool, interface{}, string) { | ||||
|  | ||||
| 	didPanic := false | ||||
| 	var message interface{} | ||||
| 	var stack string | ||||
| 	func() { | ||||
|  | ||||
| 		defer func() { | ||||
| 			if message = recover(); message != nil { | ||||
| 				didPanic = true | ||||
| 				stack = string(debug.Stack()) | ||||
| 			} | ||||
| 		}() | ||||
|  | ||||
| 		// call the target function | ||||
| 		f() | ||||
| func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) { | ||||
| 	didPanic = true | ||||
|  | ||||
| 	defer func() { | ||||
| 		message = recover() | ||||
| 		if didPanic { | ||||
| 			stack = string(debug.Stack()) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	return didPanic, message, stack | ||||
| 	// call the target function | ||||
| 	f() | ||||
| 	didPanic = false | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Panics asserts that the code inside the specified PanicTestFunc panics. | ||||
| @@ -1111,6 +1146,27 @@ func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // WithinRange asserts that a time is within a time range (inclusive). | ||||
| // | ||||
| //   assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) | ||||
| func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
|  | ||||
| 	if end.Before(start) { | ||||
| 		return Fail(t, "Start should be before end", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	if actual.Before(start) { | ||||
| 		return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...) | ||||
| 	} else if actual.After(end) { | ||||
| 		return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func toFloat(x interface{}) (float64, bool) { | ||||
| 	var xf float64 | ||||
| 	xok := true | ||||
| @@ -1161,11 +1217,15 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs | ||||
| 	bf, bok := toFloat(actual) | ||||
|  | ||||
| 	if !aok || !bok { | ||||
| 		return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...) | ||||
| 		return Fail(t, "Parameters must be numerical", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	if math.IsNaN(af) && math.IsNaN(bf) { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	if math.IsNaN(af) { | ||||
| 		return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...) | ||||
| 		return Fail(t, "Expected must not be NaN", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	if math.IsNaN(bf) { | ||||
| @@ -1188,7 +1248,7 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn | ||||
| 	if expected == nil || actual == nil || | ||||
| 		reflect.TypeOf(actual).Kind() != reflect.Slice || | ||||
| 		reflect.TypeOf(expected).Kind() != reflect.Slice { | ||||
| 		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) | ||||
| 		return Fail(t, "Parameters must be slice", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	actualSlice := reflect.ValueOf(actual) | ||||
| @@ -1250,8 +1310,12 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m | ||||
|  | ||||
| func calcRelativeError(expected, actual interface{}) (float64, error) { | ||||
| 	af, aok := toFloat(expected) | ||||
| 	if !aok { | ||||
| 		return 0, fmt.Errorf("expected value %q cannot be converted to float", expected) | ||||
| 	bf, bok := toFloat(actual) | ||||
| 	if !aok || !bok { | ||||
| 		return 0, fmt.Errorf("Parameters must be numerical") | ||||
| 	} | ||||
| 	if math.IsNaN(af) && math.IsNaN(bf) { | ||||
| 		return 0, nil | ||||
| 	} | ||||
| 	if math.IsNaN(af) { | ||||
| 		return 0, errors.New("expected value must not be NaN") | ||||
| @@ -1259,10 +1323,6 @@ func calcRelativeError(expected, actual interface{}) (float64, error) { | ||||
| 	if af == 0 { | ||||
| 		return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error") | ||||
| 	} | ||||
| 	bf, bok := toFloat(actual) | ||||
| 	if !bok { | ||||
| 		return 0, fmt.Errorf("actual value %q cannot be converted to float", actual) | ||||
| 	} | ||||
| 	if math.IsNaN(bf) { | ||||
| 		return 0, errors.New("actual value must not be NaN") | ||||
| 	} | ||||
| @@ -1298,7 +1358,7 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m | ||||
| 	if expected == nil || actual == nil || | ||||
| 		reflect.TypeOf(actual).Kind() != reflect.Slice || | ||||
| 		reflect.TypeOf(expected).Kind() != reflect.Slice { | ||||
| 		return Fail(t, fmt.Sprintf("Parameters must be slice"), msgAndArgs...) | ||||
| 		return Fail(t, "Parameters must be slice", msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	actualSlice := reflect.ValueOf(actual) | ||||
| @@ -1375,6 +1435,27 @@ func EqualError(t TestingT, theError error, errString string, msgAndArgs ...inte | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // ErrorContains asserts that a function returned an error (i.e. not `nil`) | ||||
| // and that the error contains the specified substring. | ||||
| // | ||||
| //   actualObj, err := SomeFunction() | ||||
| //   assert.ErrorContains(t, err,  expectedErrorSubString) | ||||
| func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool { | ||||
| 	if h, ok := t.(tHelper); ok { | ||||
| 		h.Helper() | ||||
| 	} | ||||
| 	if !Error(t, theError, msgAndArgs...) { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	actual := theError.Error() | ||||
| 	if !strings.Contains(actual, contains) { | ||||
| 		return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...) | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // matchRegexp return true if a specified regexp matches a string. | ||||
| func matchRegexp(rx interface{}, str interface{}) bool { | ||||
|  | ||||
| @@ -1588,12 +1669,17 @@ func diff(expected interface{}, actual interface{}) string { | ||||
| 	} | ||||
|  | ||||
| 	var e, a string | ||||
| 	if et != reflect.TypeOf("") { | ||||
| 		e = spewConfig.Sdump(expected) | ||||
| 		a = spewConfig.Sdump(actual) | ||||
| 	} else { | ||||
|  | ||||
| 	switch et { | ||||
| 	case reflect.TypeOf(""): | ||||
| 		e = reflect.ValueOf(expected).String() | ||||
| 		a = reflect.ValueOf(actual).String() | ||||
| 	case reflect.TypeOf(time.Time{}): | ||||
| 		e = spewConfigStringerEnabled.Sdump(expected) | ||||
| 		a = spewConfigStringerEnabled.Sdump(actual) | ||||
| 	default: | ||||
| 		e = spewConfig.Sdump(expected) | ||||
| 		a = spewConfig.Sdump(actual) | ||||
| 	} | ||||
|  | ||||
| 	diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ | ||||
| @@ -1625,6 +1711,14 @@ var spewConfig = spew.ConfigState{ | ||||
| 	MaxDepth:                10, | ||||
| } | ||||
|  | ||||
| var spewConfigStringerEnabled = spew.ConfigState{ | ||||
| 	Indent:                  " ", | ||||
| 	DisablePointerAddresses: true, | ||||
| 	DisableCapacities:       true, | ||||
| 	SortKeys:                true, | ||||
| 	MaxDepth:                10, | ||||
| } | ||||
|  | ||||
| type tHelper interface { | ||||
| 	Helper() | ||||
| } | ||||
|   | ||||
							
								
								
									
										78
									
								
								vendor/gopkg.in/yaml.v3/decode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										78
									
								
								vendor/gopkg.in/yaml.v3/decode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -100,7 +100,10 @@ func (p *parser) peek() yaml_event_type_t { | ||||
| 	if p.event.typ != yaml_NO_EVENT { | ||||
| 		return p.event.typ | ||||
| 	} | ||||
| 	if !yaml_parser_parse(&p.parser, &p.event) { | ||||
| 	// It's curious choice from the underlying API to generally return a | ||||
| 	// positive result on success, but on this case return true in an error | ||||
| 	// scenario. This was the source of bugs in the past (issue #666). | ||||
| 	if !yaml_parser_parse(&p.parser, &p.event) || p.parser.error != yaml_NO_ERROR { | ||||
| 		p.fail() | ||||
| 	} | ||||
| 	return p.event.typ | ||||
| @@ -320,6 +323,8 @@ type decoder struct { | ||||
| 	decodeCount int | ||||
| 	aliasCount  int | ||||
| 	aliasDepth  int | ||||
|  | ||||
| 	mergedFields map[interface{}]bool | ||||
| } | ||||
|  | ||||
| var ( | ||||
| @@ -808,6 +813,11 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	mergedFields := d.mergedFields | ||||
| 	d.mergedFields = nil | ||||
|  | ||||
| 	var mergeNode *Node | ||||
|  | ||||
| 	mapIsNew := false | ||||
| 	if out.IsNil() { | ||||
| 		out.Set(reflect.MakeMap(outt)) | ||||
| @@ -815,11 +825,18 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { | ||||
| 	} | ||||
| 	for i := 0; i < l; i += 2 { | ||||
| 		if isMerge(n.Content[i]) { | ||||
| 			d.merge(n.Content[i+1], out) | ||||
| 			mergeNode = n.Content[i+1] | ||||
| 			continue | ||||
| 		} | ||||
| 		k := reflect.New(kt).Elem() | ||||
| 		if d.unmarshal(n.Content[i], k) { | ||||
| 			if mergedFields != nil { | ||||
| 				ki := k.Interface() | ||||
| 				if mergedFields[ki] { | ||||
| 					continue | ||||
| 				} | ||||
| 				mergedFields[ki] = true | ||||
| 			} | ||||
| 			kkind := k.Kind() | ||||
| 			if kkind == reflect.Interface { | ||||
| 				kkind = k.Elem().Kind() | ||||
| @@ -833,6 +850,12 @@ func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	d.mergedFields = mergedFields | ||||
| 	if mergeNode != nil { | ||||
| 		d.merge(n, mergeNode, out) | ||||
| 	} | ||||
|  | ||||
| 	d.stringMapType = stringMapType | ||||
| 	d.generalMapType = generalMapType | ||||
| 	return true | ||||
| @@ -844,7 +867,8 @@ func isStringMap(n *Node) bool { | ||||
| 	} | ||||
| 	l := len(n.Content) | ||||
| 	for i := 0; i < l; i += 2 { | ||||
| 		if n.Content[i].ShortTag() != strTag { | ||||
| 		shortTag := n.Content[i].ShortTag() | ||||
| 		if shortTag != strTag && shortTag != mergeTag { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| @@ -861,7 +885,6 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { | ||||
| 	var elemType reflect.Type | ||||
| 	if sinfo.InlineMap != -1 { | ||||
| 		inlineMap = out.Field(sinfo.InlineMap) | ||||
| 		inlineMap.Set(reflect.New(inlineMap.Type()).Elem()) | ||||
| 		elemType = inlineMap.Type().Elem() | ||||
| 	} | ||||
|  | ||||
| @@ -870,6 +893,9 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { | ||||
| 		d.prepare(n, field) | ||||
| 	} | ||||
|  | ||||
| 	mergedFields := d.mergedFields | ||||
| 	d.mergedFields = nil | ||||
| 	var mergeNode *Node | ||||
| 	var doneFields []bool | ||||
| 	if d.uniqueKeys { | ||||
| 		doneFields = make([]bool, len(sinfo.FieldsList)) | ||||
| @@ -879,13 +905,20 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { | ||||
| 	for i := 0; i < l; i += 2 { | ||||
| 		ni := n.Content[i] | ||||
| 		if isMerge(ni) { | ||||
| 			d.merge(n.Content[i+1], out) | ||||
| 			mergeNode = n.Content[i+1] | ||||
| 			continue | ||||
| 		} | ||||
| 		if !d.unmarshal(ni, name) { | ||||
| 			continue | ||||
| 		} | ||||
| 		if info, ok := sinfo.FieldsMap[name.String()]; ok { | ||||
| 		sname := name.String() | ||||
| 		if mergedFields != nil { | ||||
| 			if mergedFields[sname] { | ||||
| 				continue | ||||
| 			} | ||||
| 			mergedFields[sname] = true | ||||
| 		} | ||||
| 		if info, ok := sinfo.FieldsMap[sname]; ok { | ||||
| 			if d.uniqueKeys { | ||||
| 				if doneFields[info.Id] { | ||||
| 					d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type())) | ||||
| @@ -911,6 +944,11 @@ func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) { | ||||
| 			d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type())) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	d.mergedFields = mergedFields | ||||
| 	if mergeNode != nil { | ||||
| 		d.merge(n, mergeNode, out) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| @@ -918,19 +956,29 @@ func failWantMap() { | ||||
| 	failf("map merge requires map or sequence of maps as the value") | ||||
| } | ||||
|  | ||||
| func (d *decoder) merge(n *Node, out reflect.Value) { | ||||
| 	switch n.Kind { | ||||
| func (d *decoder) merge(parent *Node, merge *Node, out reflect.Value) { | ||||
| 	mergedFields := d.mergedFields | ||||
| 	if mergedFields == nil { | ||||
| 		d.mergedFields = make(map[interface{}]bool) | ||||
| 		for i := 0; i < len(parent.Content); i += 2 { | ||||
| 			k := reflect.New(ifaceType).Elem() | ||||
| 			if d.unmarshal(parent.Content[i], k) { | ||||
| 				d.mergedFields[k.Interface()] = true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch merge.Kind { | ||||
| 	case MappingNode: | ||||
| 		d.unmarshal(n, out) | ||||
| 		d.unmarshal(merge, out) | ||||
| 	case AliasNode: | ||||
| 		if n.Alias != nil && n.Alias.Kind != MappingNode { | ||||
| 		if merge.Alias != nil && merge.Alias.Kind != MappingNode { | ||||
| 			failWantMap() | ||||
| 		} | ||||
| 		d.unmarshal(n, out) | ||||
| 		d.unmarshal(merge, out) | ||||
| 	case SequenceNode: | ||||
| 		// Step backwards as earlier nodes take precedence. | ||||
| 		for i := len(n.Content) - 1; i >= 0; i-- { | ||||
| 			ni := n.Content[i] | ||||
| 		for i := 0; i < len(merge.Content); i++ { | ||||
| 			ni := merge.Content[i] | ||||
| 			if ni.Kind == AliasNode { | ||||
| 				if ni.Alias != nil && ni.Alias.Kind != MappingNode { | ||||
| 					failWantMap() | ||||
| @@ -943,6 +991,8 @@ func (d *decoder) merge(n *Node, out reflect.Value) { | ||||
| 	default: | ||||
| 		failWantMap() | ||||
| 	} | ||||
|  | ||||
| 	d.mergedFields = mergedFields | ||||
| } | ||||
|  | ||||
| func isMerge(n *Node) bool { | ||||
|   | ||||
							
								
								
									
										11
									
								
								vendor/gopkg.in/yaml.v3/parserc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/gopkg.in/yaml.v3/parserc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -687,6 +687,9 @@ func yaml_parser_parse_node(parser *yaml_parser_t, event *yaml_event_t, block, i | ||||
| func yaml_parser_parse_block_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { | ||||
| 	if first { | ||||
| 		token := peek_token(parser) | ||||
| 		if token == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		parser.marks = append(parser.marks, token.start_mark) | ||||
| 		skip_token(parser) | ||||
| 	} | ||||
| @@ -786,7 +789,7 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { | ||||
| 	} | ||||
|  | ||||
| 	token := peek_token(parser) | ||||
| 	if token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { | ||||
| 	if token == nil || token.typ != yaml_BLOCK_SEQUENCE_START_TOKEN && token.typ != yaml_BLOCK_MAPPING_START_TOKEN { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -813,6 +816,9 @@ func yaml_parser_split_stem_comment(parser *yaml_parser_t, stem_len int) { | ||||
| func yaml_parser_parse_block_mapping_key(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { | ||||
| 	if first { | ||||
| 		token := peek_token(parser) | ||||
| 		if token == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		parser.marks = append(parser.marks, token.start_mark) | ||||
| 		skip_token(parser) | ||||
| 	} | ||||
| @@ -922,6 +928,9 @@ func yaml_parser_parse_block_mapping_value(parser *yaml_parser_t, event *yaml_ev | ||||
| func yaml_parser_parse_flow_sequence_entry(parser *yaml_parser_t, event *yaml_event_t, first bool) bool { | ||||
| 	if first { | ||||
| 		token := peek_token(parser) | ||||
| 		if token == nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		parser.marks = append(parser.marks, token.start_mark) | ||||
| 		skip_token(parser) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @@ -178,6 +178,10 @@ github.com/jesseduffield/gocui | ||||
| # github.com/jesseduffield/kill v0.0.0-20220618033138-bfbe04675d10 | ||||
| ## explicit; go 1.18 | ||||
| github.com/jesseduffield/kill | ||||
| # github.com/jesseduffield/lazycore v0.0.0-20221009152330-3297d5700785 | ||||
| ## explicit; go 1.18 | ||||
| github.com/jesseduffield/lazycore/pkg/boxlayout | ||||
| github.com/jesseduffield/lazycore/pkg/utils | ||||
| # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e | ||||
| ## explicit; go 1.15 | ||||
| github.com/jesseduffield/minimal/gitignore | ||||
| @@ -235,7 +239,7 @@ github.com/rivo/uniseg | ||||
| # github.com/sahilm/fuzzy v0.1.0 | ||||
| ## explicit | ||||
| github.com/sahilm/fuzzy | ||||
| # github.com/samber/lo v1.10.1 | ||||
| # github.com/samber/lo v1.31.0 | ||||
| ## explicit; go 1.18 | ||||
| github.com/samber/lo | ||||
| # github.com/sanity-io/litter v1.5.2 | ||||
| @@ -253,7 +257,7 @@ github.com/sirupsen/logrus | ||||
| # github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad | ||||
| ## explicit | ||||
| github.com/spkg/bom | ||||
| # github.com/stretchr/testify v1.7.0 | ||||
| # github.com/stretchr/testify v1.8.0 | ||||
| ## explicit; go 1.13 | ||||
| github.com/stretchr/testify/assert | ||||
| # github.com/xanzy/ssh-agent v0.2.1 | ||||
| @@ -312,6 +316,6 @@ gopkg.in/ozeidan/fuzzy-patricia.v3/patricia | ||||
| # gopkg.in/warnings.v0 v0.1.2 | ||||
| ## explicit | ||||
| gopkg.in/warnings.v0 | ||||
| # gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b | ||||
| # gopkg.in/yaml.v3 v3.0.1 | ||||
| ## explicit | ||||
| gopkg.in/yaml.v3 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user