Skip to content

Casting GVec[T]/DMat[T] safely to compatible type #72

@arkanoid87

Description

@arkanoid87

I'm using vmath with types defined with unchained while working with spatio-temporal data.
Both libs work at compile time, and both roots their functionality on the float type.

I'm dealing with the issue of safely converting DVec/DMat to float based types, like GVec2[Meter] or GVec2[Second] and back to GVec2[float].

A simple cast seems to accomplish the job. Another Nim user helped me by adding when not compiles(T(arr[0])) compile time check alike, but I feel that a solution should exist within vmath.

What's your opinion about adding a safe float-to-floatlike conversion? Do you know a better way to add this functionality into vmath that would span GVec234[T] and GMat234[T]?

import vmath
import unchained

type
  GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T]
  GMat234[T] = GMat2[T] | GMat3[T] | GMat4[T]
  GStuff[T] = GVec234[T] | GMat234[T]

# failing attemps for a shorter solution
# import std/typetraits
# proc asType*[T](arr: GStuff[T], Y: typedesc): GStuff[Y] =
#   when not compiles(Y(arr[0])):
#     {.error: "Incorrect base type conv".}
#   cast[(genericHead(typeof(arr)))[Y]](arr)

# template asType*[T](arr: var GStuff[T], Y: typedesc): var GStuff[Y] =
#   when not compiles(T(arr[0])):
#     {.error: "Incorrect base type conv".}
#   cast[ptr typeof(arr).genericHead()](addr arr)

template asType*[T](arr: GStuff[T], Y: typedesc): GStuff[Y] =
  when not compiles(Y(arr[0])):
    {.error: "Incorrect base type conv".}
  when arr is GVec2[T]:
    cast[GVec2[Y]](arr)
  elif arr is GVec3[T]:
    cast[GVec3[Y]](arr)
  elif arr is GVec4[T]:
    cast[GVec4[Y]](arr)
  elif arr is GMat2[T]:
    cast[GMat2[Y]](arr)
  elif arr is GMat3[T]:
    cast[GMat3[Y]](arr)
  else:
    cast[GMat4[Y]](arr)

template asType*[T](arr: var GStuff[T], Y: typedesc): var GStuff[Y] =
  when not compiles(Y(arr[0])):
    {.error: "Incorrect base type conv".}
  when arr is GVec2[T]:
    cast[ptr GVec2[Y]](addr arr)[]
  elif arr is GVec3[T]:
    cast[ptr GVec3[Y]](addr arr)[]
  elif arr is GVec4[T]:
    cast[ptr GVec4[Y]](addr arr)[]
  elif arr is GMat2[T]:
    cast[ptr GMat2[Y]](addr arr)[]
  elif arr is GMat3[T]:
    cast[ptr GMat3[Y]](addr arr)[]
  else:
    cast[ptr GMat4[Y]](addr arr)[]

proc main() =
  let p1 = gvec2(1.Meter, 2.Meter)
  echo p1

  let p2 = p1.asType(float)
  echo p2

  let p3 = p2.asType(Meter)
  echo p3

  var p4 = gvec3(1.Second, 2.Second, 3.Second)
  echo p4

  var p5 = p4.asType(float)
  echo p5

  var p6 = p5.asType(Second)
  echo p6

main()

Thanks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions