github.com/mitranim/gg@v0.1.17/misc.go (about) 1 package gg 2 3 import ( 4 "context" 5 "database/sql/driver" 6 ) 7 8 var ( 9 Indent = ` ` 10 Space = ` ` 11 Newline = "\n" 12 ) 13 14 // Does nothing. 15 func Nop() {} 16 17 // Does nothing. 18 func Nop1[A any](A) {} 19 20 // Does nothing. 21 func Nop2[A, B any](A, B) {} 22 23 // Does nothing. 24 func Nop3[A, B, C any](A, B, C) {} 25 26 // Identity function. Returns input as-is. 27 func Id1[A any](val A) A { return val } 28 29 // Identity function. Returns input as-is. 30 func Id2[A, B any](val0 A, val1 B) (A, B) { return val0, val1 } 31 32 // Identity function. Returns input as-is. 33 func Id3[A, B, C any](val0 A, val1 B, val2 C) (A, B, C) { return val0, val1, val2 } 34 35 // Returns a zero value of the given type. 36 func Zero[A any]() (_ A) { return } 37 38 /* 39 Same as Go's `+` operator, expressed as a generic function. Input type may be 40 numeric or ~string. When the input type is numeric, this is unchecked and may 41 overflow. For integers, prefer `Add` whenever possible, which has overflow 42 checks. 43 */ 44 func Plus2[A Plusable](one, two A) A { return one + two } 45 46 /* 47 Variadic version of Go's `+` operator. Input type may be numeric or ~string. 48 If the input is empty, returns a zero value. Use caution: this has no overflow 49 checks for numbers. Prefer `Add` for integers. 50 */ 51 func Plus[A Plusable](val ...A) A { return Foldz(val, Plus2[A]) } 52 53 /* 54 Shortcut for implementing `driver.Valuer` on `Nullable` types that wrap other 55 types, such as `Opt`. Mostly for internal use. 56 */ 57 func ValueNull[A any, B NullableValGetter[A]](src B) (driver.Value, error) { 58 if src.IsNull() { 59 return nil, nil 60 } 61 62 val := src.Get() 63 64 impl, _ := AnyNoEscUnsafe(val).(driver.Valuer) 65 if impl != nil { 66 return impl.Value() 67 } 68 69 return val, nil 70 } 71 72 /* 73 Returns true if the given `any` can be usefully converted into a value of the 74 given type. If the result is true, `src.(A)` doesn't panic. If the output is 75 false, `src.(A)` panics. 76 */ 77 func AnyIs[A any](src any) bool { 78 _, ok := AnyNoEscUnsafe(src).(A) 79 return ok 80 } 81 82 /* 83 Non-asserting interface conversion. Converts the given `any` into the given 84 type, returning zero value on failure. 85 */ 86 func AnyAs[A any](src any) A { 87 val, _ := AnyNoEscUnsafe(src).(A) 88 return val 89 } 90 91 /* 92 Converts the argument to `any` and returns it. Sometimes useful in higher-order 93 functions. 94 */ 95 func ToAny[A any](val A) any { return val } 96 97 /* 98 Uses `context.WithValue` to create a context with the given value, using the 99 type's nil pointer "(*A)(nil)" as the key. 100 */ 101 func CtxSet[A any](ctx context.Context, val A) context.Context { 102 return context.WithValue(ctx, (*A)(nil), val) 103 } 104 105 /* 106 Uses `ctx.Value` to get the value of the given type, using the type's nil pointer 107 "(*A)(nil)" as the key. If the context is nil or doesn't contain the value, 108 returns zero value and false. 109 */ 110 func CtxGot[A any](ctx context.Context) (A, bool) { 111 if ctx == nil { 112 return Zero[A](), false 113 } 114 val, ok := ctx.Value((*A)(nil)).(A) 115 return val, ok 116 } 117 118 // Same as `CtxGot` but returns only the boolean. 119 func CtxHas[A any](ctx context.Context) bool { 120 _, ok := CtxGot[A](ctx) 121 return ok 122 } 123 124 /* 125 Same as `CtxGot` but returns only the resulting value. If value was not found, 126 output is zero. 127 */ 128 func CtxGet[A any](ctx context.Context) A { 129 val, _ := CtxGot[A](ctx) 130 return val 131 } 132 133 /* 134 Short for "iterator". Returns a slice of the given length that can be iterated 135 by using a `range` loop. Usage: 136 137 for range Iter(size) { ... } 138 for ind := range Iter(size) { ... } 139 140 Because `struct{}` is zero-sized, `[]struct{}` is backed by "zerobase" (see Go 141 source → "runtime/malloc.go") and does not allocate. Loops using this should 142 compile to approximately the same instructions as "normal" counted loops. 143 */ 144 func Iter(size int) []struct{} { return make([]struct{}, size) } 145 146 /* 147 Returns a slice of numbers from `min` to `max`. The range is inclusive at the 148 start but exclusive at the end: `[min,max)`. If `!(max > min)`, returns nil. 149 Values must be within the range of the Go type `int`. 150 */ 151 func Range[A Int](min, max A) []A { 152 // We must check this before calling `max-1` to avoid underflow. 153 if !(max > min) { 154 return nil 155 } 156 return RangeIncl(min, max-1) 157 } 158 159 /* 160 Returns a slice of numbers from `min` to `max`. The range is inclusive at the 161 start and at the end: `[min,max]`. If `!(max >= min)`, returns nil. Values must 162 be within the range of the Go type `int`. 163 164 While the exclusive range `[min,max)` implemented by `Range` is more 165 traditional, this function allows to create a range that includes the maximum 166 representable value of any given integer type, such as 255 for `uint8`, which 167 cannot be done with `Range`. 168 */ 169 func RangeIncl[A Int](min, max A) []A { 170 if !(max >= min) { 171 return nil 172 } 173 174 minInt := NumConv[int](min) 175 maxInt := NumConv[int](max) 176 buf := make([]A, (maxInt-minInt)+1) 177 for ind := range buf { 178 buf[ind] = A(ind + minInt) 179 } 180 return buf 181 } 182 183 // Shortcut for creating range `[0,N)`, exclusive at the end. 184 func Span[A Int](val A) []A { return Range(0, val) } 185 186 /* 187 Takes a pointer and a fallback value which must be non-zero. If the pointer 188 destination is zero, sets the fallback and returns true. Otherwise returns 189 false. 190 */ 191 func Fellback[A any](tar *A, fallback A) bool { 192 if IsZero(fallback) { 193 panic(Errf(`invalid non-zero fallback %#v`, fallback)) 194 } 195 196 if tar == nil { 197 return false 198 } 199 200 if IsZero(*tar) { 201 *tar = fallback 202 return true 203 } 204 return false 205 } 206 207 /* 208 Snapshots the current value at the given pointer and returns a snapshot 209 that can restore this value. Usage: 210 211 defer Snap(&somePtr).Done() 212 somePtr.SomeField = someValue 213 */ 214 func Snap[A any](ptr *A) Snapshot[A] { return Snapshot[A]{ptr, *ptr} } 215 216 /* 217 Snapshots the previous value, sets the next value, and returns a snapshot 218 that can restore the previous value. Usage: 219 220 defer SnapSwap(&somePtr, someVal).Done() 221 */ 222 func SnapSwap[A any](ptr *A, next A) Snapshot[A] { 223 prev := *ptr 224 *ptr = next 225 return Snapshot[A]{ptr, prev} 226 } 227 228 // Short for "snapshot". Used by `SnapSwap`. 229 type Snapshot[A any] struct { 230 Ptr *A 231 Val A 232 } 233 234 // If the pointer is non-nil, writes the value to it. See `SnapSwap`. 235 func (self Snapshot[_]) Done() { 236 if self.Ptr != nil { 237 *self.Ptr = self.Val 238 } 239 } 240 241 /* 242 Snapshots the length of the given slice and returns a snapshot that can restore 243 the previous length. Usage: 244 245 defer SnapSlice(&somePtr).Done() 246 */ 247 func SnapSlice[Slice ~[]Elem, Elem any](ptr *Slice) SliceSnapshot[Slice, Elem] { 248 return SliceSnapshot[Slice, Elem]{ptr, PtrLen(ptr)} 249 } 250 251 /* 252 Analogous to `Snapshot`, but instead of storing a value, stores a length. 253 When done, reverts the referenced slice to the given length. 254 */ 255 type SliceSnapshot[Slice ~[]Elem, Elem any] struct { 256 Ptr *Slice 257 Len int 258 } 259 260 /* 261 Analogous to `Snapshot.Done`. Reverts the referenced slice to `self.Len` while 262 keeping the capacity. 263 */ 264 func (self SliceSnapshot[_, _]) Done() { 265 if self.Ptr != nil { 266 *self.Ptr = (*self.Ptr)[:self.Len] 267 } 268 } 269 270 // Shortcut for making a pseudo-tuple with two elements. 271 func Tuple2[A, B any](valA A, valB B) Tup2[A, B] { 272 return Tup2[A, B]{valA, valB} 273 } 274 275 // Represents a pseudo-tuple with two elements. 276 type Tup2[A, B any] struct { 277 A A 278 B B 279 } 280 281 // Converts the pseudo-tuple to a proper Go tuple. 282 func (self Tup2[A, B]) Get() (A, B) { return self.A, self.B } 283 284 // Shortcut for making a pseudo-tuple with three elements. 285 func Tuple3[A, B, C any](valA A, valB B, valC C) Tup3[A, B, C] { 286 return Tup3[A, B, C]{valA, valB, valC} 287 } 288 289 // Represents a pseudo-tuple with three elements. 290 type Tup3[A, B, C any] struct { 291 A A 292 B B 293 C C 294 } 295 296 // Converts the pseudo-tuple to a proper Go tuple. 297 func (self Tup3[A, B, C]) Get() (A, B, C) { return self.A, self.B, self.C } 298 299 /* 300 Makes a zero value of the given type, passes it to the given mutator functions 301 by pointer, and returns the modified value. Nil functions are ignored. 302 */ 303 func With[A any](funs ...func(*A)) (out A) { 304 for _, fun := range funs { 305 if fun != nil { 306 fun(&out) 307 } 308 } 309 return 310 }