|  | 
| 1 |  | -// Copyright 2024 The Hugo Authors. All rights reserved. | 
|  | 1 | +// Copyright 2025 The Hugo Authors. All rights reserved. | 
| 2 | 2 | // Some functions in this file (see comments) is based on the Go source code, | 
| 3 | 3 | // copyright The Go Authors and  governed by a BSD-style license. | 
| 4 | 4 | // | 
| @@ -318,37 +318,119 @@ func IsContextType(tp reflect.Type) bool { | 
| 318 | 318 | // This conversion is lossless. | 
| 319 | 319 | // See Issue 14079. | 
| 320 | 320 | func ConvertIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { | 
|  | 321 | +	if val.Kind() == reflect.Interface { | 
|  | 322 | +		val = val.Elem() | 
|  | 323 | +	} | 
|  | 324 | + | 
|  | 325 | +	if val.Type().AssignableTo(typ) { | 
|  | 326 | +		// No conversion needed. | 
|  | 327 | +		return val, true | 
|  | 328 | +	} | 
|  | 329 | + | 
| 321 | 330 | 	if IsInt(typ.Kind()) { | 
| 322 |  | -		if IsInt(val.Kind()) { | 
| 323 |  | -			if typ.OverflowInt(val.Int()) { | 
| 324 |  | -				return reflect.Value{}, false | 
| 325 |  | -			} | 
| 326 |  | -			return val.Convert(typ), true | 
|  | 331 | +		return convertToIntIfPossible(val, typ) | 
|  | 332 | +	} | 
|  | 333 | +	if IsFloat(typ.Kind()) { | 
|  | 334 | +		return convertToFloatIfPossible(val, typ) | 
|  | 335 | +	} | 
|  | 336 | +	if IsUint(typ.Kind()) { | 
|  | 337 | +		return convertToUintIfPossible(val, typ) | 
|  | 338 | +	} | 
|  | 339 | +	return reflect.Value{}, false | 
|  | 340 | +} | 
|  | 341 | + | 
|  | 342 | +func convertToUintIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { | 
|  | 343 | +	if IsInt(val.Kind()) { | 
|  | 344 | +		i := val.Int() | 
|  | 345 | +		if i < 0 { | 
|  | 346 | +			return reflect.Value{}, false | 
| 327 | 347 | 		} | 
| 328 |  | -		if IsUint(val.Kind()) { | 
| 329 |  | -			if val.Uint() > uint64(math.MaxInt64) { | 
| 330 |  | -				return reflect.Value{}, false | 
| 331 |  | -			} | 
| 332 |  | -			if typ.OverflowInt(int64(val.Uint())) { | 
| 333 |  | -				return reflect.Value{}, false | 
| 334 |  | -			} | 
| 335 |  | -			return val.Convert(typ), true | 
|  | 348 | +		u := uint64(i) | 
|  | 349 | +		if typ.OverflowUint(u) { | 
|  | 350 | +			return reflect.Value{}, false | 
| 336 | 351 | 		} | 
| 337 |  | -		if IsFloat(val.Kind()) { | 
| 338 |  | -			f := val.Float() | 
| 339 |  | -			if f < float64(math.MinInt64) || f > float64(math.MaxInt64) { | 
| 340 |  | -				return reflect.Value{}, false | 
| 341 |  | -			} | 
| 342 |  | -			i := int64(f) | 
| 343 |  | -			if typ.OverflowInt(i) { | 
| 344 |  | -				return reflect.Value{}, false | 
| 345 |  | -			} | 
| 346 |  | -			// Check for lossless conversion. | 
| 347 |  | -			if float64(i) != f { | 
| 348 |  | -				return reflect.Value{}, false | 
| 349 |  | -			} | 
| 350 |  | -			return val.Convert(typ), true | 
|  | 352 | +		return reflect.ValueOf(u).Convert(typ), true | 
|  | 353 | +	} | 
|  | 354 | +	if IsUint(val.Kind()) { | 
|  | 355 | +		if typ.OverflowUint(val.Uint()) { | 
|  | 356 | +			return reflect.Value{}, false | 
| 351 | 357 | 		} | 
|  | 358 | +		return val.Convert(typ), true | 
| 352 | 359 | 	} | 
|  | 360 | +	if IsFloat(val.Kind()) { | 
|  | 361 | +		f := val.Float() | 
|  | 362 | +		if f < 0 || f > float64(math.MaxUint64) { | 
|  | 363 | +			return reflect.Value{}, false | 
|  | 364 | +		} | 
|  | 365 | +		if f != math.Trunc(f) { | 
|  | 366 | +			return reflect.Value{}, false | 
|  | 367 | +		} | 
|  | 368 | +		u := uint64(f) | 
|  | 369 | +		if typ.OverflowUint(u) { | 
|  | 370 | +			return reflect.Value{}, false | 
|  | 371 | +		} | 
|  | 372 | +		return reflect.ValueOf(u).Convert(typ), true | 
|  | 373 | +	} | 
|  | 374 | +	return reflect.Value{}, false | 
|  | 375 | +} | 
|  | 376 | + | 
|  | 377 | +func convertToFloatIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { | 
|  | 378 | +	if IsInt(val.Kind()) { | 
|  | 379 | +		i := val.Int() | 
|  | 380 | +		f := float64(i) | 
|  | 381 | +		if typ.OverflowFloat(f) { | 
|  | 382 | +			return reflect.Value{}, false | 
|  | 383 | +		} | 
|  | 384 | +		return reflect.ValueOf(f).Convert(typ), true | 
|  | 385 | +	} | 
|  | 386 | +	if IsUint(val.Kind()) { | 
|  | 387 | +		u := val.Uint() | 
|  | 388 | +		f := float64(u) | 
|  | 389 | +		if typ.OverflowFloat(f) { | 
|  | 390 | +			return reflect.Value{}, false | 
|  | 391 | +		} | 
|  | 392 | +		return reflect.ValueOf(f).Convert(typ), true | 
|  | 393 | +	} | 
|  | 394 | +	if IsFloat(val.Kind()) { | 
|  | 395 | +		if typ.OverflowFloat(val.Float()) { | 
|  | 396 | +			return reflect.Value{}, false | 
|  | 397 | +		} | 
|  | 398 | +		return val.Convert(typ), true | 
|  | 399 | +	} | 
|  | 400 | + | 
|  | 401 | +	return reflect.Value{}, false | 
|  | 402 | +} | 
|  | 403 | + | 
|  | 404 | +func convertToIntIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { | 
|  | 405 | +	if IsInt(val.Kind()) { | 
|  | 406 | +		if typ.OverflowInt(val.Int()) { | 
|  | 407 | +			return reflect.Value{}, false | 
|  | 408 | +		} | 
|  | 409 | +		return val.Convert(typ), true | 
|  | 410 | +	} | 
|  | 411 | +	if IsUint(val.Kind()) { | 
|  | 412 | +		if val.Uint() > uint64(math.MaxInt64) { | 
|  | 413 | +			return reflect.Value{}, false | 
|  | 414 | +		} | 
|  | 415 | +		if typ.OverflowInt(int64(val.Uint())) { | 
|  | 416 | +			return reflect.Value{}, false | 
|  | 417 | +		} | 
|  | 418 | +		return val.Convert(typ), true | 
|  | 419 | +	} | 
|  | 420 | +	if IsFloat(val.Kind()) { | 
|  | 421 | +		f := val.Float() | 
|  | 422 | +		if f < float64(math.MinInt64) || f > float64(math.MaxInt64) { | 
|  | 423 | +			return reflect.Value{}, false | 
|  | 424 | +		} | 
|  | 425 | +		if f != math.Trunc(f) { | 
|  | 426 | +			return reflect.Value{}, false | 
|  | 427 | +		} | 
|  | 428 | +		if typ.OverflowInt(int64(f)) { | 
|  | 429 | +			return reflect.Value{}, false | 
|  | 430 | +		} | 
|  | 431 | +		return reflect.ValueOf(int64(f)).Convert(typ), true | 
|  | 432 | + | 
|  | 433 | +	} | 
|  | 434 | + | 
| 353 | 435 | 	return reflect.Value{}, false | 
| 354 | 436 | } | 
0 commit comments