github.com/astrogo/fitsio@v0.3.0/column.go (about) 1 // Copyright 2015 The astrogo Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package fitsio 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "strconv" 12 "strings" 13 ) 14 15 // Column represents a column in a FITS table 16 type Column struct { 17 Name string // column name, corresponding to ``TTYPE`` keyword 18 Format string // column format, corresponding to ``TFORM`` keyword 19 Unit string // column unit, corresponding to ``TUNIT`` keyword 20 Null string // null value, corresponding to ``TNULL`` keyword 21 Bscale float64 // bscale value, corresponding to ``TSCAL`` keyword 22 Bzero float64 // bzero value, corresponding to ``TZERO`` keyword 23 Display string // display format, corresponding to ``TDISP`` keyword 24 Dim []int64 // column dimension corresponding to ``TDIM`` keyword 25 Start int64 // column starting position, corresponding to ``TBCOL`` keyword 26 27 dtype Type // type of the value held by the column 28 offset int // offset in bytes (from start of data-pad or heap-pad) to get at the column data 29 txtfmt string // go-based fmt string for ASCII table 30 31 // read function (binary/ascii) 32 read func(table *Table, icol int, irow int64, ptr interface{}) error 33 34 // write function (binary/ascii) 35 write func(table *Table, icol int, irow int64, ptr interface{}) error 36 } 37 38 // NewColumn creates a new Column with name `name` and Format inferred from the type of value 39 func NewColumn(name string, v interface{}) (Column, error) { 40 panic("not implemented") 41 } 42 43 // Type returns the Go reflect.Type associated with this Column 44 func (col *Column) Type() reflect.Type { 45 return col.dtype.gotype 46 } 47 48 // readBin reads the value at column number icol and row irow, into ptr. 49 func (col *Column) readBin(table *Table, icol int, irow int64, ptr interface{}) error { 50 var err error 51 52 rv := reflect.Indirect(reflect.ValueOf(ptr)) 53 rt := reflect.TypeOf(rv.Interface()) 54 55 switch rt.Kind() { 56 case reflect.Slice: 57 58 beg := table.rowsz*int(irow) + col.offset 59 end := beg + col.dtype.dsize 60 row := table.data[beg:end] 61 r := newReader(row) 62 slice := reflect.ValueOf(ptr).Elem() 63 nmax := 0 64 65 switch col.dtype.dsize { 66 case 8: 67 var n int32 68 var offset int32 69 r.readI32(&n) 70 r.readI32(&offset) 71 beg = int(offset) 72 end = beg + int(n)*int(col.dtype.gotype.Elem().Size()) 73 nmax = int(n) 74 75 case 16: 76 var n int64 77 var offset int64 78 r.readI64(&n) 79 r.readI64(&offset) 80 beg = int(offset) 81 end = beg + int(n)*int(col.dtype.gotype.Elem().Size()) 82 nmax = int(n) 83 } 84 if slice.Len() < nmax { 85 slice = reflect.MakeSlice(rt, nmax, nmax) 86 } 87 88 r = newReader(table.heap[beg:end]) 89 switch slice := slice.Interface().(type) { 90 case []bool: 91 r.readBools(slice[:nmax]) 92 93 case []byte: 94 copy(slice[:nmax], r.p) 95 96 case []int8: 97 r.readI8s(slice[:nmax]) 98 99 case []int16: 100 r.readI16s(slice[:nmax]) 101 102 case []int32: 103 r.readI32s(slice[:nmax]) 104 105 case []int64: 106 r.readI64s(slice[:nmax]) 107 108 case []int: 109 r.readInts(slice[:nmax]) 110 111 case []uint16: 112 r.readU16s(slice[:nmax]) 113 114 case []uint32: 115 r.readU32s(slice[:nmax]) 116 117 case []uint64: 118 r.readU64s(slice[:nmax]) 119 120 case []uint: 121 r.readUints(slice[:nmax]) 122 123 case []float32: 124 r.readF32s(slice[:nmax]) 125 126 case []float64: 127 r.readF64s(slice[:nmax]) 128 129 case []complex64: 130 r.readC64s(slice[:nmax]) 131 132 case []complex128: 133 r.readC128s(slice[:nmax]) 134 135 default: 136 panic(fmt.Errorf("fitsio: not implemented %T", slice)) 137 } 138 rv.Set(slice) 139 140 case reflect.Array: 141 142 beg := table.rowsz*int(irow) + col.offset 143 end := beg + (col.dtype.dsize * col.dtype.len) 144 row := table.data[beg:end] 145 r := newReader(row) 146 switch slice := rv.Slice(0, rv.Len()).Interface().(type) { 147 case []bool: 148 r.readBools(slice) 149 150 case []byte: 151 copy(slice, r.p) 152 153 case []int8: 154 r.readI8s(slice) 155 156 case []int16: 157 r.readI16s(slice) 158 159 case []int32: 160 r.readI32s(slice) 161 162 case []int64: 163 r.readI64s(slice) 164 165 case []int: 166 r.readInts(slice) 167 168 case []uint16: 169 r.readU16s(slice) 170 171 case []uint32: 172 r.readU32s(slice) 173 174 case []uint64: 175 r.readU64s(slice) 176 177 case []uint: 178 r.readUints(slice) 179 180 case []float32: 181 r.readF32s(slice) 182 183 case []float64: 184 r.readF64s(slice) 185 186 case []complex64: 187 r.readC64s(slice) 188 189 case []complex128: 190 r.readC128s(slice) 191 192 default: 193 panic(fmt.Errorf("fitsio: not implemented %T", slice)) 194 } 195 196 case reflect.Bool: 197 198 beg := table.rowsz*int(irow) + col.offset 199 end := beg + col.dtype.dsize 200 201 r := newReader(table.data[beg:end]) 202 r.readBool(ptr.(*bool)) 203 204 case reflect.Int8: 205 206 beg := table.rowsz*int(irow) + col.offset 207 end := beg + col.dtype.dsize 208 209 r := newReader(table.data[beg:end]) 210 r.readI8(ptr.(*int8)) 211 212 case reflect.Int16: 213 214 beg := table.rowsz*int(irow) + col.offset 215 end := beg + col.dtype.dsize 216 217 r := newReader(table.data[beg:end]) 218 r.readI16(ptr.(*int16)) 219 220 case reflect.Int32: 221 222 beg := table.rowsz*int(irow) + col.offset 223 end := beg + col.dtype.dsize 224 225 r := newReader(table.data[beg:end]) 226 r.readI32(ptr.(*int32)) 227 228 case reflect.Int64: 229 230 beg := table.rowsz*int(irow) + col.offset 231 end := beg + col.dtype.dsize 232 233 r := newReader(table.data[beg:end]) 234 r.readI64(ptr.(*int64)) 235 236 case reflect.Int: 237 238 beg := table.rowsz*int(irow) + col.offset 239 end := beg + col.dtype.dsize 240 241 r := newReader(table.data[beg:end]) 242 r.readInt(ptr.(*int)) 243 244 case reflect.Uint8: 245 246 beg := table.rowsz*int(irow) + col.offset 247 end := beg + col.dtype.dsize 248 249 r := newReader(table.data[beg:end]) 250 r.readU8(ptr.(*uint8)) 251 252 case reflect.Uint16: 253 254 beg := table.rowsz*int(irow) + col.offset 255 end := beg + col.dtype.dsize 256 257 r := newReader(table.data[beg:end]) 258 r.readU16(ptr.(*uint16)) 259 260 case reflect.Uint32: 261 262 beg := table.rowsz*int(irow) + col.offset 263 end := beg + col.dtype.dsize 264 265 r := newReader(table.data[beg:end]) 266 r.readU32(ptr.(*uint32)) 267 268 case reflect.Uint64: 269 270 beg := table.rowsz*int(irow) + col.offset 271 end := beg + col.dtype.dsize 272 273 r := newReader(table.data[beg:end]) 274 r.readU64(ptr.(*uint64)) 275 276 case reflect.Uint: 277 278 beg := table.rowsz*int(irow) + col.offset 279 end := beg + col.dtype.dsize 280 281 r := newReader(table.data[beg:end]) 282 r.readUint(ptr.(*uint)) 283 284 case reflect.Float32: 285 286 beg := table.rowsz*int(irow) + col.offset 287 end := beg + col.dtype.dsize 288 289 r := newReader(table.data[beg:end]) 290 r.readF32(ptr.(*float32)) 291 292 case reflect.Float64: 293 294 beg := table.rowsz*int(irow) + col.offset 295 end := beg + col.dtype.dsize 296 297 r := newReader(table.data[beg:end]) 298 r.readF64(ptr.(*float64)) 299 300 case reflect.Complex64: 301 302 beg := table.rowsz*int(irow) + col.offset 303 end := beg + col.dtype.dsize 304 305 r := newReader(table.data[beg:end]) 306 r.readC64(ptr.(*complex64)) 307 308 case reflect.Complex128: 309 310 beg := table.rowsz*int(irow) + col.offset 311 end := beg + col.dtype.dsize 312 313 r := newReader(table.data[beg:end]) 314 r.readC128(ptr.(*complex128)) 315 316 case reflect.String: 317 318 beg := table.rowsz*int(irow) + col.offset 319 end := beg + col.dtype.dsize 320 row := table.data[beg:end] 321 str := "" 322 if row[0] == '\x00' { 323 str = string(row[1:]) 324 str = strings.TrimRight(str, string([]byte("\x00"))) 325 } else { 326 str = string(row) 327 } 328 329 rv.SetString(str) 330 331 default: 332 return fmt.Errorf("fitsio: binary-table can not read/write %v", rt.Kind()) 333 } 334 return err 335 } 336 337 // writeBin writes the value at column number icol and row irow, from ptr. 338 func (col *Column) writeBin(table *Table, icol int, irow int64, ptr interface{}) error { 339 var ( 340 err error 341 rv = reflect.Indirect(reflect.ValueOf(ptr)) 342 rvi = rv.Interface() 343 rt = reflect.TypeOf(rvi) 344 ) 345 346 switch rt.Kind() { 347 case reflect.Slice: 348 349 beg := table.rowsz*int(irow) + col.offset 350 end := beg + col.dtype.dsize 351 352 w := newWriter(table.data[beg:end]) 353 nmax := rv.Len() 354 355 switch col.dtype.dsize { 356 case 8: 357 w.writeI32(int32(nmax)) 358 w.writeI32(int32(len(table.heap))) 359 360 case 16: 361 w.writeI64(int64(nmax)) 362 w.writeI64(int64(len(table.heap))) 363 } 364 365 { 366 w := newWriter(make([]byte, nmax*col.dtype.hsize)) 367 switch slice := rvi.(type) { 368 case []bool: 369 w.writeBools(slice) 370 371 case []byte: 372 copy(w.p, slice) 373 374 case []int8: 375 w.writeI8s(slice) 376 377 case []int16: 378 w.writeI16s(slice) 379 380 case []int32: 381 w.writeI32s(slice) 382 383 case []int64: 384 w.writeI64s(slice) 385 386 case []int: 387 w.writeInts(slice) 388 389 case []uint16: 390 w.writeU16s(slice) 391 392 case []uint32: 393 w.writeU32s(slice) 394 395 case []uint64: 396 w.writeU64s(slice) 397 398 case []uint: 399 w.writeUints(slice) 400 401 case []float32: 402 w.writeF32s(slice) 403 404 case []float64: 405 w.writeF64s(slice) 406 407 case []complex64: 408 w.writeC64s(slice) 409 410 case []complex128: 411 w.writeC128s(slice) 412 413 default: 414 panic(fmt.Errorf("fitsio: not implemented %T", slice)) 415 } 416 table.heap = append(table.heap, w.bytes()...) 417 } 418 419 case reflect.Array: 420 421 beg := table.rowsz*int(irow) + col.offset 422 end := beg + (col.dtype.dsize * col.dtype.len) 423 424 w := newWriter(table.data[beg:end]) 425 switch slice := rv.Slice(0, rv.Len()).Interface().(type) { 426 case []bool: 427 w.writeBools(slice) 428 429 case []byte: 430 copy(w.p, slice) 431 432 case []int8: 433 w.writeI8s(slice) 434 435 case []int16: 436 w.writeI16s(slice) 437 438 case []int32: 439 w.writeI32s(slice) 440 441 case []int64: 442 w.writeI64s(slice) 443 444 case []int: 445 w.writeInts(slice) 446 447 case []uint16: 448 w.writeU16s(slice) 449 450 case []uint32: 451 w.writeU32s(slice) 452 453 case []uint64: 454 w.writeU64s(slice) 455 456 case []uint: 457 w.writeUints(slice) 458 459 case []float32: 460 w.writeF32s(slice) 461 462 case []float64: 463 w.writeF64s(slice) 464 465 case []complex64: 466 w.writeC64s(slice) 467 468 case []complex128: 469 w.writeC128s(slice) 470 471 default: 472 panic(fmt.Errorf("fitsio: not implemented %T", slice)) 473 } 474 475 case reflect.Bool: 476 477 beg := table.rowsz*int(irow) + col.offset 478 end := beg + col.dtype.dsize 479 480 w := newWriter(table.data[beg:end]) 481 w.writeBool(rvi.(bool)) 482 483 case reflect.Int8: 484 485 beg := table.rowsz*int(irow) + col.offset 486 end := beg + col.dtype.dsize 487 488 w := newWriter(table.data[beg:end]) 489 w.writeI8(rvi.(int8)) 490 491 case reflect.Int16: 492 493 beg := table.rowsz*int(irow) + col.offset 494 end := beg + col.dtype.dsize 495 496 w := newWriter(table.data[beg:end]) 497 w.writeI16(rvi.(int16)) 498 499 case reflect.Int32: 500 501 beg := table.rowsz*int(irow) + col.offset 502 end := beg + col.dtype.dsize 503 504 w := newWriter(table.data[beg:end]) 505 w.writeI32(rvi.(int32)) 506 507 case reflect.Int64: 508 509 beg := table.rowsz*int(irow) + col.offset 510 end := beg + col.dtype.dsize 511 512 w := newWriter(table.data[beg:end]) 513 w.writeI64(rvi.(int64)) 514 515 case reflect.Int: 516 517 beg := table.rowsz*int(irow) + col.offset 518 end := beg + col.dtype.dsize 519 520 w := newWriter(table.data[beg:end]) 521 w.writeInt(rvi.(int)) 522 523 case reflect.Uint8: 524 525 beg := table.rowsz*int(irow) + col.offset 526 end := beg + col.dtype.dsize 527 528 w := newWriter(table.data[beg:end]) 529 w.writeU8(rvi.(uint8)) 530 531 case reflect.Uint16: 532 533 beg := table.rowsz*int(irow) + col.offset 534 end := beg + col.dtype.dsize 535 536 w := newWriter(table.data[beg:end]) 537 w.writeU16(rvi.(uint16)) 538 539 case reflect.Uint32: 540 541 beg := table.rowsz*int(irow) + col.offset 542 end := beg + col.dtype.dsize 543 544 w := newWriter(table.data[beg:end]) 545 w.writeU32(rvi.(uint32)) 546 547 case reflect.Uint64: 548 549 beg := table.rowsz*int(irow) + col.offset 550 end := beg + col.dtype.dsize 551 552 w := newWriter(table.data[beg:end]) 553 w.writeU64(rvi.(uint64)) 554 555 case reflect.Uint: 556 557 beg := table.rowsz*int(irow) + col.offset 558 end := beg + col.dtype.dsize 559 560 w := newWriter(table.data[beg:end]) 561 w.writeUint(rvi.(uint)) 562 563 case reflect.Float32: 564 565 beg := table.rowsz*int(irow) + col.offset 566 end := beg + col.dtype.dsize 567 568 w := newWriter(table.data[beg:end]) 569 w.writeF32(rvi.(float32)) 570 571 case reflect.Float64: 572 573 beg := table.rowsz*int(irow) + col.offset 574 end := beg + col.dtype.dsize 575 576 w := newWriter(table.data[beg:end]) 577 w.writeF64(rvi.(float64)) 578 579 case reflect.Complex64: 580 581 beg := table.rowsz*int(irow) + col.offset 582 end := beg + col.dtype.dsize 583 584 w := newWriter(table.data[beg:end]) 585 w.writeC64(rvi.(complex64)) 586 587 case reflect.Complex128: 588 589 beg := table.rowsz*int(irow) + col.offset 590 end := beg + col.dtype.dsize 591 592 w := newWriter(table.data[beg:end]) 593 w.writeC128(rvi.(complex128)) 594 595 case reflect.String: 596 597 beg := table.rowsz*int(irow) + col.offset 598 end := beg + col.dtype.dsize 599 600 buf := newWriter(table.data[beg:end]) 601 str := rv.String() 602 data := make([]byte, 0, len(str)+1) 603 data = append(data, '\x00') 604 data = append(data, []byte(str)...) 605 n := len(data) 606 if n > end-beg { 607 n = end - beg 608 } 609 if n < end-beg { 610 data = append(data, bytes.Repeat([]byte("\x00"), end-beg-n)...) 611 n = len(data) 612 } 613 _, err = buf.Write(data[:n]) 614 615 if err != nil { 616 return fmt.Errorf("fitsio: %v\n", err) 617 } 618 619 default: 620 return fmt.Errorf("fitsio: binary-table can not read/write %v", rt.Kind()) 621 } 622 623 return err 624 } 625 626 // readTxt reads the value at column number icol and row irow, into ptr. 627 func (col *Column) readTxt(table *Table, icol int, irow int64, ptr interface{}) error { 628 var err error 629 630 rv := reflect.Indirect(reflect.ValueOf(ptr)) 631 rt := reflect.TypeOf(rv.Interface()) 632 633 beg := table.rowsz*int(irow) + col.offset 634 end := beg + col.dtype.dsize 635 buf := table.data[beg:end] 636 str := strings.TrimSpace(string(buf)) 637 638 switch rt.Kind() { 639 case reflect.Slice: 640 641 return fmt.Errorf("fitsio: ASCII-table can not read/write slices") 642 643 case reflect.Array: 644 645 return fmt.Errorf("fitsio: ASCII-table can not read/write arrays") 646 647 case reflect.Bool: 648 649 return fmt.Errorf("fitsio: ASCII-table can not read/write booleans") 650 651 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 652 v, err := strconv.ParseUint(str, 10, 64) 653 if err != nil { 654 return fmt.Errorf("fitsio: error parsing %q into a uint: %v", str, err) 655 } 656 rv.SetUint(v) 657 658 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 659 v, err := strconv.ParseInt(str, 10, 64) 660 if err != nil { 661 return fmt.Errorf("fitsio: error parsing %q into an int: %v", str, err) 662 } 663 rv.SetInt(v) 664 665 case reflect.Float32, reflect.Float64: 666 667 v, err := strconv.ParseFloat(str, 64) 668 if err != nil { 669 return fmt.Errorf("fitsio: error parsing %q into a float: %v", str, err) 670 } 671 rv.SetFloat(v) 672 673 case reflect.Complex64, reflect.Complex128: 674 675 return fmt.Errorf("fitsio: ASCII-table can not read/write complexes") 676 677 case reflect.String: 678 rv.SetString(str) 679 680 default: 681 return fmt.Errorf("fitsio: ASCII-table can not read/write %v", rt.Kind()) 682 } 683 return err 684 } 685 686 // writeTxt writes the value at column number icol and row irow, from ptr. 687 func (col *Column) writeTxt(table *Table, icol int, irow int64, ptr interface{}) error { 688 var err error 689 690 beg := table.rowsz*int(irow) + col.offset 691 end := beg + col.dtype.dsize 692 w := newWriter(table.data[beg:end]) 693 694 rv := reflect.Indirect(reflect.ValueOf(ptr)) 695 rt := reflect.TypeOf(rv.Interface()) 696 697 switch rt.Kind() { 698 case reflect.Slice: 699 700 return fmt.Errorf("fitsio: ASCII-table can not read/write slices") 701 702 case reflect.Array: 703 704 return fmt.Errorf("fitsio: ASCII-table can not read/write arrays") 705 706 case reflect.Bool: 707 708 return fmt.Errorf("fitsio: ASCII-table can not read/write booleans") 709 710 case reflect.Complex64, reflect.Complex128: 711 712 return fmt.Errorf("fitsio: ASCII-table can not read/write complexes") 713 714 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 715 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 716 reflect.Float32, reflect.Float64, 717 reflect.String: 718 719 str := fmt.Sprintf(col.txtfmt, rv.Interface()) 720 n := 0 721 n, err = fmt.Fprintf(w, str) 722 if err != nil { 723 return fmt.Errorf("fitsio: error writing '%#v': %v", rv.Interface(), err) 724 } 725 if n != len(w.p) { 726 return fmt.Errorf( 727 "fitsio: error writing '%#v'. expected %d bytes. wrote %d", 728 rv.Interface(), len(w.p), n, 729 ) 730 } 731 732 default: 733 return fmt.Errorf("fitsio: ASCII-table can not read/write %v", rt.Kind()) 734 } 735 736 return err 737 }