aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2025-08-02 12:20:35 +0100
committergingerBill <gingerBill@users.noreply.github.com>2025-08-02 12:20:35 +0100
commitbb4bc316a4bd86774953f1e8fcefffb5ed8bbf37 (patch)
treebd48bf739dd69c0bc6578fb2a69cc5823ddee6f8 /core
parentae02d3d02d2eb5132fa7c6573ed7db20d7e18f3e (diff)
`for in string16`; Support `string16` across core
Diffstat (limited to 'core')
-rw-r--r--core/c/libc/locale.odin16
-rw-r--r--core/debug/trace/trace_windows.odin2
-rw-r--r--core/dynlib/lib_windows.odin2
-rw-r--r--core/mem/virtual/virtual_windows.odin2
-rw-r--r--core/os/dir_windows.odin2
-rw-r--r--core/os/os2/file_windows.odin2
-rw-r--r--core/os/stat_windows.odin4
-rw-r--r--core/path/filepath/path_windows.odin4
-rw-r--r--core/sys/info/platform_windows.odin12
-rw-r--r--core/sys/windows/comctl32.odin10
-rw-r--r--core/sys/windows/ip_helper.odin6
-rw-r--r--core/sys/windows/types.odin4
-rw-r--r--core/sys/windows/util.odin50
-rw-r--r--core/time/timezone/tz_windows.odin8
-rw-r--r--core/unicode/utf16/utf16.odin32
15 files changed, 93 insertions, 63 deletions
diff --git a/core/c/libc/locale.odin b/core/c/libc/locale.odin
index 27317526c..3216e0f90 100644
--- a/core/c/libc/locale.odin
+++ b/core/c/libc/locale.odin
@@ -72,14 +72,14 @@ when ODIN_OS == .Windows {
n_sep_by_space: c.char,
p_sign_posn: c.char,
n_sign_posn: c.char,
- _W_decimal_point: [^]u16 `fmt:"s,0"`,
- _W_thousands_sep: [^]u16 `fmt:"s,0"`,
- _W_int_curr_symbol: [^]u16 `fmt:"s,0"`,
- _W_currency_symbol: [^]u16 `fmt:"s,0"`,
- _W_mon_decimal_point: [^]u16 `fmt:"s,0"`,
- _W_mon_thousands_sep: [^]u16 `fmt:"s,0"`,
- _W_positive_sign: [^]u16 `fmt:"s,0"`,
- _W_negative_sign: [^]u16 `fmt:"s,0"`,
+ _W_decimal_point: cstring16,
+ _W_thousands_sep: cstring16,
+ _W_int_curr_symbol: cstring16,
+ _W_currency_symbol: cstring16,
+ _W_mon_decimal_point: cstring16,
+ _W_mon_thousands_sep: cstring16,
+ _W_positive_sign: cstring16,
+ _W_negative_sign: cstring16,
}
} else {
lconv :: struct {
diff --git a/core/debug/trace/trace_windows.odin b/core/debug/trace/trace_windows.odin
index 96507714c..04e92f125 100644
--- a/core/debug/trace/trace_windows.odin
+++ b/core/debug/trace/trace_windows.odin
@@ -54,7 +54,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (
symbol.SizeOfStruct = size_of(symbol^)
symbol.MaxNameLen = 255
if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
- fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator)
+ fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator)
} else {
fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
}
diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin
index 05cd2cb3c..95372dac6 100644
--- a/core/dynlib/lib_windows.odin
+++ b/core/dynlib/lib_windows.odin
@@ -13,7 +13,7 @@ _LIBRARY_FILE_EXTENSION :: "dll"
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
wide_path := win32.utf8_to_wstring(path, allocator)
- defer free(wide_path, allocator)
+ defer free(rawptr(wide_path), allocator)
handle := cast(Library)win32.LoadLibraryW(wide_path)
return handle, handle != nil
}
diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin
index 0da8498d5..3fd4eeb68 100644
--- a/core/mem/virtual/virtual_windows.odin
+++ b/core/mem/virtual/virtual_windows.odin
@@ -72,7 +72,7 @@ foreign Kernel32 {
flProtect: u32,
dwMaximumSizeHigh: u32,
dwMaximumSizeLow: u32,
- lpName: [^]u16,
+ lpName: cstring16,
) -> rawptr ---
MapViewOfFile :: proc(
diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin
index ae3e6922c..40f4b9e9b 100644
--- a/core/os/dir_windows.odin
+++ b/core/os/dir_windows.odin
@@ -87,7 +87,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
defer delete(path)
find_data := &win32.WIN32_FIND_DATAW{}
- find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data)
+ find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
if find_handle == win32.INVALID_HANDLE_VALUE {
err = get_last_error()
return dfi[:], err
diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin
index 40d012183..1134e765c 100644
--- a/core/os/os2/file_windows.odin
+++ b/core/os/os2/file_windows.odin
@@ -619,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error {
return .Unsupported
}
-_open_sym_link :: proc(p: [^]u16) -> (handle: win32.HANDLE, err: Error) {
+_open_sym_link :: proc(p: cstring16) -> (handle: win32.HANDLE, err: Error) {
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS)
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil)
diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin
index ca4f87668..662c9f9e6 100644
--- a/core/os/stat_windows.odin
+++ b/core/os/stat_windows.odin
@@ -17,7 +17,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
buf := make([dynamic]u16, 100)
defer delete(buf)
for {
- n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 {
return "", get_last_error()
}
@@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> (
return nil, get_last_error()
}
buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
- buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0)
+ buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
return buf[:buf_len], nil
}
@(private, require_results)
diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin
index 0dcb28cf8..24c6e00a5 100644
--- a/core/path/filepath/path_windows.odin
+++ b/core/path/filepath/path_windows.odin
@@ -61,13 +61,13 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
}
p := win32.utf8_to_utf16(name, ta)
- n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
+ n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 {
return "", os.get_last_error()
}
buf := make([]u16, n, ta)
- n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+ n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 {
delete(buf)
return "", os.get_last_error()
diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin
index 4c00ddadf..dd1441d30 100644
--- a/core/sys/info/platform_windows.odin
+++ b/core/sys/info/platform_windows.odin
@@ -324,8 +324,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_SZ,
nil,
raw_data(result_wide[:]),
@@ -359,8 +359,8 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool
result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_DWORD,
nil,
&res,
@@ -386,8 +386,8 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool
result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW(
hkey,
- &key_name_wide[0],
- &val_name_wide[0],
+ cstring16(&key_name_wide[0]),
+ cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_QWORD,
nil,
&res,
diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin
index d954f952c..c7a166634 100644
--- a/core/sys/windows/comctl32.odin
+++ b/core/sys/windows/comctl32.odin
@@ -573,10 +573,10 @@ Button_GetTextMargin :: #force_inline proc "system" (hwnd: HWND, pmargin: ^RECT)
return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin))
}
Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(psz))
+ return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(rawptr(psz)))
}
Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(psz))
+ return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(rawptr(psz)))
}
Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT {
return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0)
@@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct {
PEDITBALLOONTIP :: ^EDITBALLOONTIP
Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(lpcwText))
+ return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(rawptr(lpcwText)))
}
Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL {
- return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(lpcwText))
+ return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(rawptr(lpcwText)))
}
Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText)
@@ -1197,7 +1197,7 @@ ListView_GetItemPosition :: #force_inline proc "system" (hwnd: HWND, i: c_int, p
return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt))
}
ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int {
- return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(psz))
+ return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(rawptr(psz)))
}
ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int {
return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo))
diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin
index 7a6e545ac..d2e75d531 100644
--- a/core/sys/windows/ip_helper.odin
+++ b/core/sys/windows/ip_helper.odin
@@ -38,9 +38,9 @@ IP_Adapter_Addresses :: struct {
FirstAnycastAddress: ^IP_ADAPTER_ANYCAST_ADDRESS_XP,
FirstMulticastAddress: ^IP_ADAPTER_MULTICAST_ADDRESS_XP,
FirstDnsServerAddress: ^IP_ADAPTER_DNS_SERVER_ADDRESS_XP,
- DnsSuffix: ^u16,
- Description: ^u16,
- FriendlyName: ^u16,
+ DnsSuffix: cstring16,
+ Description: cstring16,
+ FriendlyName: cstring16,
PhysicalAddress: [8]u8,
PhysicalAddressLength: u32,
Anonymous2: struct #raw_union {
diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin
index 92b1cb15c..be16d2fdd 100644
--- a/core/sys/windows/types.odin
+++ b/core/sys/windows/types.odin
@@ -107,8 +107,8 @@ PDWORD64 :: ^DWORD64
PDWORD_PTR :: ^DWORD_PTR
ATOM :: distinct WORD
-wstring :: [^]WCHAR
-PWSTR :: [^]WCHAR
+wstring :: cstring16
+PWSTR :: cstring16
PBYTE :: ^BYTE
LPBYTE :: ^BYTE
diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin
index 995e8e0e5..10dc907e7 100644
--- a/core/sys/windows/util.odin
+++ b/core/sys/windows/util.odin
@@ -122,14 +122,14 @@ utf8_to_utf16 :: proc{utf8_to_utf16_alloc, utf8_to_utf16_buf}
utf8_to_wstring_alloc :: proc(s: string, allocator := context.temp_allocator) -> wstring {
if res := utf8_to_utf16(s, allocator); len(res) > 0 {
- return raw_data(res)
+ return wstring(raw_data(res))
}
return nil
}
utf8_to_wstring_buf :: proc(buf: []u16, s: string) -> wstring {
if res := utf8_to_utf16(buf, s); len(res) > 0 {
- return raw_data(res)
+ return wstring(raw_data(res))
}
return nil
}
@@ -215,7 +215,7 @@ utf16_to_utf8_alloc :: proc(s: []u16, allocator := context.temp_allocator) -> (r
if len(s) == 0 {
return "", nil
}
- return wstring_to_utf8(raw_data(s), len(s), allocator)
+ return wstring_to_utf8(wstring(raw_data(s)), len(s), allocator)
}
/*
@@ -236,7 +236,7 @@ utf16_to_utf8_buf :: proc(buf: []u8, s: []u16) -> (res: string) {
if len(s) == 0 {
return
}
- return wstring_to_utf8(buf, raw_data(s), len(s))
+ return wstring_to_utf8(buf, wstring(raw_data(s)), len(s))
}
utf16_to_utf8 :: proc{utf16_to_utf8_alloc, utf16_to_utf8_buf}
@@ -298,7 +298,7 @@ _add_user :: proc(servername: string, username: string, password: string) -> (ok
servername_w = nil
} else {
server := utf8_to_utf16(servername, context.temp_allocator)
- servername_w = &server[0]
+ servername_w = wstring(&server[0])
}
if len(username) == 0 || len(username) > LM20_UNLEN {
@@ -348,7 +348,7 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s
res := LookupAccountNameW(
nil, // Look on this computer first
- &username_w[0],
+ wstring(&username_w[0]),
&sid,
&cbsid,
nil,
@@ -364,10 +364,10 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s
res = LookupAccountNameW(
nil,
- &username_w[0],
+ wstring(&username_w[0]),
&sid,
&cbsid,
- &cname_w[0],
+ wstring(&cname_w[0]),
&computer_name_size,
&pe_use,
)
@@ -390,7 +390,7 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) {
res := LookupAccountNameW(
nil, // Look on this computer first
- &username_w[0],
+ wstring(&username_w[0]),
sid,
&cbsid,
nil,
@@ -406,10 +406,10 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) {
res = LookupAccountNameW(
nil,
- &username_w[0],
+ wstring(&username_w[0]),
sid,
&cbsid,
- &cname_w[0],
+ wstring(&cname_w[0]),
&computer_name_size,
&pe_use,
)
@@ -428,7 +428,7 @@ add_user_to_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) {
group_name := utf8_to_utf16(group, context.temp_allocator)
ok = NetLocalGroupAddMembers(
nil,
- &group_name[0],
+ wstring(&group_name[0]),
0,
&group_member,
1,
@@ -443,7 +443,7 @@ add_del_from_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) {
group_name := utf8_to_utf16(group, context.temp_allocator)
ok = NetLocalGroupDelMembers(
nil,
- &group_name[0],
+ cstring16(&group_name[0]),
0,
&group_member,
1,
@@ -465,19 +465,19 @@ add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) {
if res == false {
return false, ""
}
- defer LocalFree(sb)
+ defer LocalFree(rawptr(sb))
pszProfilePath := make([]u16, 257, context.temp_allocator)
res2 := CreateProfile(
sb,
- &username_w[0],
- &pszProfilePath[0],
+ cstring16(&username_w[0]),
+ cstring16(&pszProfilePath[0]),
257,
)
if res2 != 0 {
return false, ""
}
- profile_path = wstring_to_utf8(&pszProfilePath[0], 257) or_else ""
+ profile_path = wstring_to_utf8(wstring(&pszProfilePath[0]), 257) or_else ""
return true, profile_path
}
@@ -495,7 +495,7 @@ delete_user_profile :: proc(username: string) -> (ok: bool) {
if res == false {
return false
}
- defer LocalFree(sb)
+ defer LocalFree(rawptr(sb))
res2 := DeleteProfileW(
sb,
@@ -548,13 +548,13 @@ delete_user :: proc(servername: string, username: string) -> (ok: bool) {
servername_w = nil
} else {
server := utf8_to_utf16(servername, context.temp_allocator)
- servername_w = &server[0]
+ servername_w = wstring(&server[0])
}
username_w := utf8_to_utf16(username)
res := NetUserDel(
servername_w,
- &username_w[0],
+ wstring(&username_w[0]),
)
if res != .Success {
return false
@@ -586,9 +586,9 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
user_token: HANDLE
ok = bool(LogonUserW(
- lpszUsername = &username_w[0],
- lpszDomain = &domain_w[0],
- lpszPassword = &password_w[0],
+ lpszUsername = wstring(&username_w[0]),
+ lpszDomain = wstring(&domain_w[0]),
+ lpszPassword = wstring(&password_w[0]),
dwLogonType = .NEW_CREDENTIALS,
dwLogonProvider = .WINNT50,
phToken = &user_token,
@@ -605,8 +605,8 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P
ok = bool(CreateProcessAsUserW(
user_token,
- &app_w[0],
- &commandline_w[0],
+ wstring(&app_w[0]),
+ wstring(&commandline_w[0]),
nil, // lpProcessAttributes,
nil, // lpThreadAttributes,
false, // bInheritHandles,
diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin
index 8dc5f533c..fe00719a2 100644
--- a/core/time/timezone/tz_windows.odin
+++ b/core/time/timezone/tz_windows.odin
@@ -159,9 +159,9 @@ iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) ->
status: windows.UError
iana_name_wstr := windows.utf8_to_wstring(iana_name, allocator)
- defer free(iana_name_wstr, allocator)
+ defer free(rawptr(iana_name_wstr), allocator)
- wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, raw_data(wintz_name_buffer[:]), len(wintz_name_buffer), &status)
+ wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, cstring16(raw_data(wintz_name_buffer[:])), len(wintz_name_buffer), &status)
if status != .U_ZERO_ERROR {
return
}
@@ -178,7 +178,7 @@ local_tz_name :: proc(allocator := context.allocator) -> (name: string, success:
iana_name_buffer: [128]u16
status: windows.UError
- zone_str_len := windows.ucal_getDefaultTimeZone(raw_data(iana_name_buffer[:]), len(iana_name_buffer), &status)
+ zone_str_len := windows.ucal_getDefaultTimeZone(cstring16(raw_data(iana_name_buffer[:])), len(iana_name_buffer), &status)
if status != .U_ZERO_ERROR {
return
}
@@ -291,7 +291,7 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re
defer delete(tz_key, allocator)
tz_key_wstr := windows.utf8_to_wstring(tz_key, allocator)
- defer free(tz_key_wstr, allocator)
+ defer free(rawptr(tz_key_wstr), allocator)
key: windows.HKEY
res := windows.RegOpenKeyExW(windows.HKEY_LOCAL_MACHINE, tz_key_wstr, 0, windows.KEY_READ, &key)
diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin
index 9a8cfe438..d3f98584b 100644
--- a/core/unicode/utf16/utf16.odin
+++ b/core/unicode/utf16/utf16.odin
@@ -126,7 +126,37 @@ decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) {
return
}
-rune_count :: proc(s: []u16) -> (n: int) {
+string_to_runes :: proc "odin" (s: string16, allocator := context.allocator) -> (runes: []rune) {
+ n := rune_count(s)
+
+ runes = make([]rune, n, allocator)
+ i := 0
+ for r in s {
+ runes[i] = r
+ i += 1
+ }
+ return
+}
+
+
+rune_count :: proc{
+ rune_count_in_string,
+ rune_count_in_slice,
+}
+rune_count_in_string :: proc(s: string16) -> (n: int) {
+ for i := 0; i < len(s); i += 1 {
+ c := s[i]
+ if _surr1 <= c && c < _surr2 && i+1 < len(s) &&
+ _surr2 <= s[i+1] && s[i+1] < _surr3 {
+ i += 1
+ }
+ n += 1
+ }
+ return
+}
+
+
+rune_count_in_slice :: proc(s: []u16) -> (n: int) {
for i := 0; i < len(s); i += 1 {
c := s[i]
if _surr1 <= c && c < _surr2 && i+1 < len(s) &&