the easiest one is using $ operator to convert cstring to Nim string, assuming it is null terminated. then the resulted string can be iterated using Nim unicode module, assuming it is encoded in UTF8.
if it is not encoded in UTF8, you need to find another suitable library, or write it yourself, it's not that too hard if only dealing with UTF16 - UTF8 - UTF32 conversion.
if your unicode string is encoded in UTF8 and your C shared library also accept UTF8 encoded, then it is safe to export nim string to cstring. the Nim compiler will automatically handle the conversion. actually, no conversion take place, only pointer passing.
if it is not UTF8 encoded, or the C library cannot accept UTF8, you can do some conversion and pass the pointer of your unicode string to C.
#assume both of this function deals with UTF8 encoded string
proc get_c_unicode(): cstring {.importc: bla bla bla.}
proc put_c_unicode(x: cstring): cint {.importc: bla bla bla.}
var nim_unicode_string = $get_c_unicode()
#do something with unicode module
if put_c_unicode(nim_unicode_string) != 0.cint:
echo "ok"
as simple as that, if both party agree to use UTF8
unicode codepoints it self is not too hard to program, but rendering and formatting the unicode font/typeface, that is the real nightmare.