1/* 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16package std.core; 17 18/** 19 * @deprecated 20*/ 21export type NullishType = Any 22 23/** 24 * @deprecated 25*/ 26export type NullableType = Object | null 27 28/** 29 * @deprecated 30*/ 31export type Nullish<T> = T | null | undefined 32 33export type PropertyKey = string 34 35export const ARRAY_LENGTH_MEMBER_NAME = "length" 36export const FUNCTION_LENGTH_MEMBER_NAME = "length" 37export const FUNCTION_NAME_MEMBER_NAME = "name" 38 39export const OBJECT_TO_STRING_MEMBER_NAME: string = "toString" 40export const OBJECT_TO_LOCALE_STRING_MEMBER_NAME: string = "toLocaleString" 41export const OBJECT_HAS_OWN_PROPERTY_MEMBER_NAME: string = "hasOwnProperty" 42 43type EntryType = [PropertyKey, NullishType] 44type NullishEntryType = EntryType | null | undefined 45 46/** 47 * `object` is an alias for type `Object` 48 */ 49export type object = Object; 50 51/** 52 * Common ancestor amongst all other classes 53 */ 54export class Object { 55 /** 56 * Constructs a new blank Object 57 */ 58 constructor () {}; 59 60 /** 61 * Converts this object to a string 62 * 63 * @returns result of the conversion 64 */ 65 public toString(): String { 66 return Value.of(this).toString() 67 } 68 69 /** 70 * Converts this object to locale-specific string representation 71 * 72 * @returns result of the conversion 73 */ 74 public toLocaleString(): String { 75 return Value.of(this).toLocaleString() 76 } 77 78 /** 79 * Returns a hash code (integer representation) for this instance 80 * 81 * @returns representation of this instance 82 */ 83 public $_hashCode(): int { 84 return Runtime.getHashCode(this); 85 } 86 87 /** 88 * Returns an array of a given record property names 89 * 90 * @param rec a record 91 * 92 * @returns an array of strings representing the given record's property names 93 */ 94 public static keys(rec: Record<PropertyKey, NullishType>): string[] { 95 const keys: string[] = new string[rec.size.toInt()] 96 97 let i = 0 98 for (const key of rec.keys()) { 99 keys[i] = key 100 i++ 101 } 102 103 return keys 104 } 105 106 private static generateKeyArray(length: Number): string[] { 107 const len = length.toInt(); 108 if (len == 0) { 109 return new string[0] 110 } 111 let res: string[] = new string[len] 112 for (let i = 0; i < len; i++) { 113 res[i] = new Int(i).toString() 114 } 115 return res 116 } 117 118 /** 119 * Returns the names of the fields of an object 120 * 121 * @param o an object 122 * 123 * @returns an array of strings representing the given object's own string-keyed field keys. 124 */ 125 public static keys(o: Object): string[] { 126 // Char, Boolean and Numeric types doesn't have keys 127 if (o instanceof Char || 128 o instanceof Boolean || 129 o instanceof Byte || 130 o instanceof Short || 131 o instanceof Int || 132 o instanceof Long || 133 o instanceof Float || 134 o instanceof Double) { 135 return new string[0] 136 } 137 // "Keys" for the string type is enumeration from 0 to str.length - 1 138 if (o instanceof String) { 139 return Object.generateKeyArray(o.getLength()) 140 } else if (o instanceof Array) { 141 return Object.generateKeyArray(o.length) 142 } 143 const t = Type.of(o) 144 if (t instanceof ClassType) { 145 const ct = t as ClassType 146 const fnum = ct.getFieldsNum() 147 if (fnum == 0) { 148 return new string[0] 149 } 150 let n: int = 0 151 for (let i = 0; i < fnum; i++) { 152 if (!ct.getField(i).isStatic()) { 153 n++ 154 } 155 } 156 let res: string[] = new string[n] 157 let j: int = 0 158 for (let i = 0; i < fnum; i++) { 159 let f = ct.getField(i) 160 if (!f.isStatic()) { 161 res[j] = f.getName() 162 j++ 163 } 164 } 165 return res 166 } else if (t instanceof ArrayType) { 167 const av = Value.of(o) as ArrayValue 168 return Object.generateKeyArray(av.getLength()) 169 } else if (t instanceof LambdaType) { 170 return new string[0] 171 } else if (t instanceof EnumType) { 172 // NOTE(shumilov-petr): Not implemented 173 throw new Error("Not implemented") 174 } else if (t instanceof UnionType) { 175 // NOTE(shumilov-petr): Not implemented 176 throw new Error("Not implemented") 177 } else if (t instanceof TupleType) { 178 // NOTE(shumilov-petr): Not implemented 179 throw new Error("Not implemented") 180 } 181 182 throw new AssertionError("Invalid object type"); 183 } 184 185 public static values(rec: Record<PropertyKey, NullishType>): NullishType[] { 186 const vals: NullishType[] = new NullishType[rec.size.toInt()] 187 188 let i = 0 189 for (let val of rec.values()) { 190 vals[i] = val 191 i++ 192 } 193 194 return vals 195 } 196 197 /** 198 * Returns the values of the fields of an object 199 * 200 * @param o an object 201 * 202 * @returns an array containing the given object's own string-keyed field values 203 */ 204 public static values(o: Object): NullishType[] { 205 if (o instanceof Char || 206 o instanceof Boolean || 207 o instanceof Byte || 208 o instanceof Short || 209 o instanceof Int || 210 o instanceof Long || 211 o instanceof Float || 212 o instanceof Double) { 213 return new NullishType[0] 214 } 215 if (o instanceof String) { 216 const sv = o as string 217 const len = sv.getLength() 218 if (len == 0) { 219 return new NullishType[0] 220 } 221 let res: NullishType[] = new NullishType[len] 222 for (let i = 0; i < len; i++) { 223 // NOTE(shumilov-petr): must be replaced by `sv.charAt(i) as string` when #15731 will be fixed 224 res[i] = new Char(sv.charAt(i)).toString() 225 } 226 return res 227 } 228 const t = Type.of(o) 229 if (t instanceof ClassType) { 230 const cv = Value.of(o) as ClassValue 231 if (cv.getFieldsNum() == 0) { 232 return new NullishType[0] 233 } 234 const keys = Object.keys(o) 235 const len = keys.length 236 let res: NullishType[] = new NullishType[len] 237 for (let i = 0; i < len; i++) { 238 res[i] = cv.getFieldByName(keys[i]).getData() 239 } 240 return res 241 } else if (t instanceof ArrayType) { 242 const av = Value.of(o) as ArrayValue 243 const len = av.getLength() 244 if (len == 0) { 245 return new NullishType[0] 246 } 247 let res: NullishType[] = new NullishType[len.toInt()] 248 for (let i = 0; i < len; i++) { 249 res[i] = av.getElement(i).getData() 250 } 251 return res 252 } else if (t instanceof LambdaType) { 253 return new NullishType[0] 254 } else if (t instanceof EnumType) { 255 // NOTE(shumilov-petr): Not implemented 256 throw new Error("Not implemented") 257 } else if (t instanceof UnionType) { 258 // NOTE(shumilov-petr): Not implemented 259 throw new Error("Not implemented") 260 } else if (t instanceof TupleType) { 261 // NOTE(shumilov-petr): Not implemented 262 throw new Error("Not implemented") 263 } 264 265 throw new AssertionError("Invalid object type") 266 } 267 268 /** 269 * Returns an array of key/values of properties of a record 270 * 271 * @param rec record that contains the fields 272 * 273 * @returns array representation of key/value 274 */ 275 public static entries(rec: Record<PropertyKey, NullishType>): NullishEntryType[] { 276 const entries: NullishEntryType[] = new NullishEntryType[rec.size.toInt()] 277 278 let i = 0 279 for (const entry of rec.entries()) { 280 entries[i] = entry 281 i++ 282 } 283 284 return entries 285 } 286 287 /** 288 * Returns an array of key/values of properties of an object 289 * 290 * @param o object that contains the fields 291 * 292 * @returns array representation of key/value 293 */ 294 public static entries(o: Object): NullishEntryType[] { 295 if (o instanceof Char || 296 o instanceof Boolean || 297 o instanceof Byte || 298 o instanceof Short || 299 o instanceof Int || 300 o instanceof Long || 301 o instanceof Float || 302 o instanceof Double) { 303 return new NullishEntryType[0] 304 } 305 if (o instanceof String) { 306 const sv = o as string 307 const len = sv.getLength() 308 if (len == 0) { 309 return new NullishEntryType[0] 310 } 311 let res: NullishEntryType[] = new NullishEntryType[len] 312 for (let i = 0; i < len; i++) { 313 res[i] = [new Int(i).toString(), new Char(sv.charAt(i)).toString()] as EntryType 314 } 315 return res 316 } 317 const t = Type.of(o) 318 if (t instanceof ClassType) { 319 const cv = Value.of(o) as ClassValue 320 if (cv.getFieldsNum() == 0) { 321 return new NullishEntryType[0] 322 } 323 const keys = Object.keys(o) 324 const len = keys.length 325 let res: NullishEntryType[] = new NullishEntryType[len] 326 for (let i = 0; i < len; i++) { 327 res[i] = [keys[i], cv.getFieldByName(keys[i]).getData()] as EntryType 328 } 329 return res 330 } else if (t instanceof ArrayType) { 331 const av = Value.of(o) as ArrayValue 332 const len = av.getLength() 333 if (len == 0) { 334 return new NullishEntryType[0] 335 } 336 let res: NullishEntryType[] = new NullishEntryType[len.toInt()] 337 for (let i = 0; i < len; i++) { 338 res[i] = [new Int(i).toString(), av.getElement(i).getData()] as EntryType 339 } 340 return res 341 } else if (t instanceof LambdaType) { 342 return new NullishEntryType[0] 343 } else if (t instanceof EnumType) { 344 // NOTE(shumilov-petr): Not implemented 345 throw new Error("Not implemented") 346 } else if (t instanceof UnionType) { 347 // NOTE(shumilov-petr): Not implemented 348 throw new Error("Not implemented") 349 } else if (t instanceof TupleType) { 350 // NOTE(shumilov-petr): Not implemented 351 throw new Error("Not implemented") 352 } 353 354 throw new AssertionError("Invalid object type") 355 } 356 357 public static getOwnPropertyNames(rec: Record<PropertyKey, NullishType>): string[] { 358 return Object.keys(rec) 359 } 360 361 /** 362 * Returns the names of the own fields of an object 363 * 364 * @param o object that contains the own fields 365 * 366 * @returns array representation of names 367 */ 368 public static getOwnPropertyNames(o: Object): string[] { 369 if (o instanceof Char || 370 o instanceof Boolean || 371 o instanceof Byte || 372 o instanceof Short || 373 o instanceof Int || 374 o instanceof Long || 375 o instanceof Float || 376 o instanceof Double) { 377 return new string[0] 378 } 379 const t = Type.of(o) 380 if (t instanceof StringType || t instanceof ArrayType || o instanceof Array) { 381 const keys = Object.keys(o) 382 const len = keys.length 383 let res: string[] = new string[len + 1] 384 for (let i = 0; i < len; i++) { 385 res[i] = keys[i] 386 } 387 res[len] = ARRAY_LENGTH_MEMBER_NAME 388 return res 389 } 390 if (t instanceof ClassType) { 391 return Object.keys(o) 392 } else if (t instanceof LambdaType) { 393 return [FUNCTION_LENGTH_MEMBER_NAME, FUNCTION_NAME_MEMBER_NAME] 394 } else if (t instanceof EnumType) { 395 // NOTE(shumilov-petr): Not implemented 396 throw new Error("Not implemented") 397 } else if (t instanceof UnionType) { 398 // NOTE(shumilov-petr): Not implemented 399 throw new Error("Not implemented") 400 } else if (t instanceof TupleType) { 401 // NOTE(shumilov-petr): Not implemented 402 throw new Error("Not implemented") 403 } 404 405 throw new AssertionError("Invalid object type") 406 } 407 408 /** 409 * Determines whether an object has a field with the specified name 410 * 411 * @param key the string name of the field to test 412 * 413 * @returns true if the object has the specified field; false otherwise 414 */ 415 public hasOwnProperty(key: string): boolean { 416 const keys = Object.getOwnPropertyNames(this) 417 const len = keys.length 418 for(let i = 0; i < len; i++) { 419 if (keys[i] == key) { 420 return true 421 } 422 } 423 return false 424 } 425 426 /** 427 * Determines whether an object has a element with the specified index 428 * 429 * @param index the number index of the element to test 430 * 431 * @returns true if the object has the specified element; false otherwise 432 */ 433 public hasOwnProperty(index: number): boolean { 434 if ((this) instanceof String) { 435 const sv = this as String 436 const len = sv.getLength() 437 const idx = index.toLong() 438 return (0 <= idx && idx < len) 439 } 440 const t = Type.of(this) 441 if (t instanceof ArrayType) { 442 const av = Value.of(this) as ArrayValue 443 const len = av.getLength() 444 const idx = index.toLong() 445 return (0 <= idx && idx < len) 446 } else if (t instanceof EnumType) { 447 // NOTE(shumilov-petr): Not implemented 448 throw new Error("Not implemented") 449 } else if (t instanceof UnionType) { 450 // NOTE(shumilov-petr): Not implemented 451 throw new Error("Not implemented") 452 } else if (t instanceof TupleType) { 453 // NOTE(shumilov-petr): Not implemented 454 throw new Error("Not implemented") 455 } 456 return false 457 } 458 459 /** 460 * Determines whether an object has a field with the specified name 461 * 462 * @param target an object 463 * 464 * @param key the string name of the field to test 465 * 466 * @returns true if the object has the specified field; false otherwise 467 */ 468 public static hasOwn(target: Object, key: PropertyKey): boolean { 469 return target.hasOwnProperty(key) 470 } 471 472 /** 473 * Determines whether an object has a element with the specified index 474 * 475 * @param target an object 476 * 477 * @param index the number index of the element to test 478 * 479 * @returns true if the object has the specified element; false otherwise 480 */ 481 public static hasOwn(target: Object, index: number): boolean { 482 return target.hasOwnProperty(index) 483 } 484 485 /** 486 * Transforms key-value pairs into a Record. 487 * 488 * @param entries an Iterable object that contains key-value pairs 489 * 490 * @returns new Record whose properties are given by the elements of the Iterable 491 */ 492 public static fromEntries<T = NullishType>(entries: Iterable<[PropertyKey, T]>): Record<PropertyKey, T> { 493 const result = new Record<PropertyKey, T>() 494 495 const entriesIter = entries.$_iterator() 496 497 let entriesIterResult = entriesIter.next() 498 while (!entriesIterResult.done) { 499 const entry: [PropertyKey, T] | undefined = entriesIterResult.value 500 if (entry != undefined) { 501 result[entry[0] as PropertyKey] = entry[1] as T 502 } 503 504 entriesIterResult = entriesIter.next() 505 } 506 507 return result 508 } 509 510 /** 511 * Copies all own properties from one or more source objects to a target Record. 512 * 513 * @param target target Record -- what to apply the sources' properties to 514 * 515 * @param source objects containing the properties you want to apply 516 * 517 * @returns the modified target Record 518 */ 519 public static assign(target: Record<PropertyKey, NullishType>, ...source: FixedArray<Object>): Record<PropertyKey, NullishType> { 520 for (const s of source) { 521 const entries = Object.entries(s) 522 for (const e of entries) { 523 target.set(e![0] as PropertyKey, e![1] as NullishType) 524 } 525 } 526 return target 527 } 528} 529